Skip to content

Instantly share code, notes, and snippets.

@leonidk
Last active November 4, 2021 15:57
Show Gist options
  • Save leonidk/a7a34ab2243363560a1067a313f12122 to your computer and use it in GitHub Desktop.
Save leonidk/a7a34ab2243363560a1067a313f12122 to your computer and use it in GitHub Desktop.
just some voting stuff
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"\n",
"from collections import defaultdict"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_excel(\"Apparel Voting Form 2021 (Responses).xlsx\")\n",
"#df = pd.read_excel(\"RoboOrg Class T-Shirt Design Vote 2019 (Responses).xlsx\")\n",
"idx_col = 2 # 2 in '20 is shirt. 4 is color, 9 is products. In 19, 2 is all we need\n",
"# in '21, 2 is shirt, 5 is color, 6 is clothing, 7 is accessories, 8 is decorations\n",
"if False: # combine multiple options, treat as one. \n",
" valid_opt = [2,5,6,7,8] # [2,4,9]\n",
" mega_row = []\n",
" for row in df.iloc[:,valid_opt].itertuples():\n",
" new_row = [_ for _ in row if type(_)==str]\n",
" mega_row.append(', '.join(new_row) if len(new_row) > 0 else np.nan)\n",
" df['mega'] = mega_row\n",
" idx_col = list(df.columns).index('mega')\n",
"\n",
"target_col = list(df.columns)[idx_col]\n",
"df = df.dropna(subset=[target_col])\n",
"df.columns,target_col,df.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# commas as delimiters, so replace patterns with internal commas\n",
"subs = {\n",
" 'Eat, Sleep, Robotics, Repeat': 'Eat Sleep Robotics Repeat'\n",
"}\n",
"options = set()\n",
"for o in df[target_col].unique():\n",
" for k,v in subs.items():\n",
" o = o.replace(k,v)\n",
" for name in o.split(', '):\n",
" options.add(name)\n",
"options = sorted(list(options))\n",
"vectors = defaultdict(list)\n",
"for row in df.itertuples():\n",
" o = row[idx_col+1]\n",
" for k,v in subs.items():\n",
" o = o.replace(k,v)\n",
" for design in options:\n",
" vectors[design].append(design in o)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for k,v in vectors.items():\n",
" df[k] = v"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# dataframe of booleans for each option\n",
"X = df[options]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_results(X,seconds_limit=15):\n",
" all_res = {}\n",
" \n",
" Xn = X/np.array(X).sum(1,keepdims=True)\n",
" # fractional winner\n",
" res = sorted([(v,k) for k,v in Xn.sum(0).items()],reverse=True)\n",
" all_res['Frac'] = {i+1:'{1} ({0:.0f})'.format(*v) for i,v in enumerate(res)}\n",
" \n",
" # normal winner\n",
" res = sorted([(v,k) for k,v in X.sum(0).items()],reverse=True)\n",
" all_res['Count'] = {i+1:'{1} ({0:.0f})'.format(*v) for i,v in enumerate(res)}\n",
" \n",
" # remove old votes\n",
" res = {}\n",
" Xc = X.copy()\n",
" while Xc.shape[0] > 0:\n",
" pop = sorted([(v,k) for k,v in Xc.sum(0).items()],reverse=True)[0][1]\n",
" st = '{1} ({0:.0f})'.format(Xc[pop].sum(),pop)\n",
" #print(st)\n",
" res[len(res)+1] = st\n",
" Xc = Xc[~Xc[pop]]\n",
" all_res['Greedy'] = res\n",
" \n",
" # seq pav. remove but give existing votes partial credit\n",
" voted = np.zeros_like(X.iloc[:,0],dtype=bool)\n",
" res = {}\n",
" selected_r = []\n",
" i = 1\n",
" while voted.sum() != X.shape[0]:\n",
" Xr = X.copy()\n",
" Xr[voted] = 1/i\n",
" pop = sorted([(v,k) for k,v in Xr.sum(0).items() if k not in selected_r],reverse=True)[0][1]\n",
" st = '{1} ({0:.0f})'.format(Xr[pop].sum(),pop)\n",
" #print(st)\n",
" res[len(res)+1] = st\n",
" voted |= Xr[pop].astype(bool)\n",
" selected_r.append(pop)\n",
" i+=1\n",
" all_res['Thiele'] = res\n",
" \n",
" # seq pav but propery credit!?\n",
" voted = np.zeros_like(X.iloc[:,0],dtype=int)\n",
" selected_r = []\n",
" i = 1\n",
" res = {}\n",
" while (voted > 0).sum() != X.shape[0]:\n",
" Xr = X.copy()\n",
" if (voted >0).sum() > 0:\n",
" Xr[voted > 0] = np.array(Xr[voted > 0])/(1+voted[voted > 0])[:,None] \n",
" pop = sorted([(v,k) for k,v in Xr.sum(0).items() if k not in selected_r],reverse=True)[0][1]\n",
" st = '{1} ({0:.0f})'.format(Xr[pop].sum(),pop)\n",
" #print(st)\n",
" res[len(res)+1] = st\n",
" voted += (Xr[pop]).astype(bool).astype(int)\n",
" selected_r.append(pop)\n",
" i+=1\n",
" all_res['Thiele_C'] = res\n",
" \n",
" # real pav. takes exponentially long, so might be slow\n",
" import itertools\n",
" import time\n",
" start_t = time.time()\n",
" resA = {}\n",
" early = False\n",
" col_i = np.arange(X.shape[1])\n",
" prev = []\n",
" prev_n = 0\n",
" for n in col_i+1:\n",
" res = []\n",
" for combo in itertools.combinations(X.columns,n):\n",
" s = (X[list(combo)].sum(1) > 0).sum()\n",
" res.append((s,combo))\n",
" if time.time() - start_t > seconds_limit:\n",
" early = True\n",
" break\n",
"\n",
" res = sorted(res,reverse=True)\n",
" new = ([_ for _ in sorted(res[0][1]) if _ not in prev] + [''])[0]\n",
" st = '{1} ({0:.0f})'.format(res[0][0]-prev_n,new)\n",
" resA[len(resA)+1] = st\n",
"\n",
" #print(st)\n",
" prev_n = res[0][0]\n",
" prev.append(new)\n",
" if prev_n == X.shape[0]:\n",
" break\n",
" if early:\n",
" break\n",
" all_res['PAV'] = resA\n",
" \n",
" return pd.DataFrame(all_res).T"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"shirt_results = get_results(X)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pd.set_option('display.max_rows', 500)\n",
"shirt_results.T"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"shirt_results."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment