Je ferai du bingo à la fête de fin d'année de l'entreprise. On vous a demandé de développer un système de bingo. Cependant, il existe les exigences suivantes (fiction).
―― "7 prix" (→ 7 gagnants) ―― "Veuillez garder le ratio de gagnants entre hommes et femmes aussi constant que possible." ―― "Veuillez garder le ratio de gagnants constant dans chaque département autant que possible." ―― "Définissez la probabilité de gagner (poids) des jeunes, des vétérans et des officiers sur 1, 2, 3"
(Référence: Histoire similaire)
Avec l'optimisation des combinaisons, vous pouvez trouver des combinaisons qui prennent en compte diverses conditions. Les gagnants sont sélectionnés et classés par ordre en fonction de la probabilité de gagner. Selon l'ordre, le $ i $ e score est de 2 $ ^ {1-i} $. En maximisant la somme des scores, nous sélectionnerons les gagnants en fonction de la probabilité de gagner autant que possible. Le ratio hommes / femmes et le ratio de départements sont soustraits de la fonction objectif en pénalisant le montant qui s'écarte du ratio.
Chargez les informations du participant dans pandas.DataFrame (si le code ne peut pas être exécuté, téléchargez le CSV à partir de l'URL et chargez-le).
import numpy as np, pandas as pd, urllib
from pulp import lpDot, lpSum
from ortoolpy import model_max, addbinvars, addvars, addvals
url = 'https://www.dropbox.com/s/refo0vfj5wbmv2h/bingo.csv?dl=1'
with urllib.request.urlopen(url) as fp:
df = pd.read_csv(fp)
Chaque ligne de DataFrame (df
) est un participant.
La probabilité de gagner (colonne Taux
) est utilisée comme un ratio pour gagner dans l'ordre avec numpy.random.choice
. Calculez le score avec cet ordre comme index et insérez-le dans la colonne Score
.
L'optimisation maximise la somme des scores.
Ajoutez une colonne de variables indiquant si vous avez gagné ou non, «Var». De plus, «pena1» est une sanction qui s'écarte du rapport hommes / femmes. Soit «pena2» le montant de la pénalité qui s'écarte du ratio d'affiliation.
nn = len(df) #Nombre de personnes
rnd = np.random.choice(df.index, nn, False, df.Rate / df.Rate.sum())
df['Score'] = pd.Series(2.0**-np.arange(nn), index=rnd) #But
addbinvars(df) #Variable ajoutée (gagnante ou non) en tant que colonne Var
pena1, pena2 = addvars(2) #Deux pénalités pour dérogation au ratio
print(df)
Name | IsMale | Div | Rate | Score | Var | |
---|---|---|---|---|---|---|
0 | Hidehito Asakura | True | Département des affaires générales | 2 | 0.000488 | v000001 |
1 | Ryoharu Miyakawa | True | Service de la comptabilité | 1 | 0.001953 | v000002 |
2 | Kenji Furuhashi | True | Département des affaires générales | 2 | 0.000977 | v000003 |
3 | Fumi Motomura | False | Département des affaires générales | 3 | 0.000015 | v000004 |
4 | Keiji Otsubo | True | Service de la comptabilité | 1 | 0.000002 | v000005 |
5 | Kazutaka Hatakeyama | True | Département des affaires générales | 2 | 0.000031 | v000006 |
6 | Wakana Takeuchi | False | Service de la comptabilité | 2 | 0.000008 | v000007 |
7 | Kana Yoda | False | Département des Ressources Humaines | 2 | 0.015625 | v000008 |
8 | Keisuke Furuta | True | Département des Ressources Humaines | 3 | 0.125000 | v000009 |
9 | Kei Ishikawa | True | Département des Ressources Humaines | 1 | 0.000061 | v000010 |
10 | Eriko Tominaga | False | Département des Ressources Humaines | 2 | 1.000000 | v000011 |
11 | Sato Tobita | False | Département des affaires générales | 1 | 0.003906 | v000012 |
12 | Seito Kamiyama | True | Département des Ressources Humaines | 2 | 0.250000 | v000013 |
13 | Ryuichiro Tabata | True | Département des affaires générales | 3 | 0.500000 | v000014 |
14 | Rie Kamei | False | Service de la comptabilité | 1 | 0.000004 | v000015 |
15 | Atsuka Sone | False | Département des affaires générales | 1 | 0.000244 | v000016 |
16 | Kiyoshiro Kasuga | True | Service de la comptabilité | 2 | 0.007812 | v000017 |
17 | Akisa Nakai | False | Service de la comptabilité | 3 | 0.062500 | v000018 |
18 | Yukio Kinjo | False | Département des Ressources Humaines | 2 | 0.031250 | v000019 |
19 | Yoshikatsu Kakinuma | True | Département des affaires générales | 1 | 0.000122 | v000020 |
Vérifiez le nombre de personnes par sexe et service.
print(df.groupby('IsMale').Div.value_counts())
IsMale Div
Faux département des ressources humaines 3
Département Comptabilité 3
Département des affaires générales 3
Véritable département des affaires générales 5
Département des ressources humaines 3
Département Comptabilité 3
Name: Div, dtype: int64
--Fonction d'objet: Somme des scores --Nombre de personnes x (Montant de l'écart par rapport au rapport entre les sexes + Montant de l'écart par rapport au rapport du département) --Restrictions --Le nombre de gagnants est de 7 --Rapport constant par sexe --Rapport constant par département
ns = 7 #Nombre de gagnants
m = model_max() #Modèle mathématique
m += lpDot(df.Score, df.Var) - nn * (pena1 + pena2) #Fonction objective
m += lpSum(df.Var) == ns #Nombre de gagnants
for _, gr in df.groupby('IsMale'): #Gardez le ratio par sexe constant
m += lpSum(gr.Var) <= ns * len(gr) / nn + pena1
for _, gr in df.groupby('Div'): #Gardez le ratio par département constant
m += lpSum(gr.Var) <= ns * len(gr) / nn + pena2
m.solve() #Solution
addvals(df) #Ajouter le résultat en tant que colonne Val
print(df[df.Val > 0]) #Gagnant
Name | IsMale | Div | Rate | Score | Var | Val | |
---|---|---|---|---|---|---|---|
10 | Eriko Tominaga | False | Département des Ressources Humaines | 2 | 1.000000 | v000011 | 1.0 |
11 | Sato Tobita | False | Département des affaires générales | 1 | 0.003906 | v000012 | 1.0 |
12 | Seito Kamiyama | True | Département des Ressources Humaines | 2 | 0.250000 | v000013 | 1.0 |
13 | Ryuichiro Tabata | True | Département des affaires générales | 3 | 0.500000 | v000014 | 1.0 |
16 | Kiyoshiro Kasuga | True | Service de la comptabilité | 2 | 0.007812 | v000017 | 1.0 |
17 | Akisa Nakai | False | Service de la comptabilité | 3 | 0.062500 | v000018 | 1.0 |
19 | Yoshikatsu Kakinuma | True | Département des affaires générales | 1 | 0.000122 | v000020 | 1.0 |
Les gagnants ont été choisis. Regardons le nombre de personnes par sexe et département.
print(df[df.Val > 0].groupby('IsMale').Div.value_counts())
IsMale Div
Faux département des ressources humaines 1
Département Comptabilité 1
Département des affaires générales 1
Véritable département des affaires générales 2
Département des ressources humaines 1
Département Comptabilité 1
Name: Div, dtype: int64
Cela semble bon.
――Une combinaison qui satisfait diverses conditions est obtenue par une méthode appelée optimisation de combinaison.
(Personnellement, j'espère qu'il n'y a pas de demande pour cet article)
c'est tout
Recommended Posts