Tengo un marco de datos y un diccionario. Necesito agregar una nueva columna al marco de datos y calcular sus valores en función del diccionario.
Aprendizaje automático, agregando nuevas características basadas en alguna tabla:
score = {(1, 45, 1, 1) : 4, (0, 1, 2, 1) : 5}
df = pd.DataFrame(data = {
'gender' : [1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
'age' : [13, 45, 1, 45, 15, 16, 16, 16, 15, 15],
'cholesterol' : [1, 2, 2, 1, 1, 1, 1, 1, 1, 1],
'smoke' : [0, 0, 1, 1, 7, 8, 3, 4, 4, 2]},
dtype = np.int64)
print(df, '\n')
df['score'] = 0
df.score = score[(df.gender, df.age, df.cholesterol, df.smoke)]
print(df)
Espero el siguiente resultado:
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
python
pandas
dataframe
dictionary
Mikola
fuente
fuente
MultiIIndex
. Alternativa:df['score'] =df.set_index(['gender', 'age', 'cholesterol', 'smoke']).index.map(score).fillna(0).to_numpy()
.df
víaset_index
, un nuevoSeries
constructor de vías. Aunque obtiene un beneficio de la alineación del índice cuando se lo asignadf['score']
. Por último,fillna(0, downcast='infer')
hace el trabajo, pero nadie debería preferir esta larga solución con la creación de muchos objetos pandas innecesariamente.merge
podría lograr. Pensé que esa respuesta se publicaría rápidamente, así que opté por una alternativa y, por alguna razón, tenía MultiIndices en mi mente. Estoy de acuerdo, esta probablemente no debería ser la respuesta aceptada, así que espero que eso no suceda.Utilizando
assign
una comprensión de lista, obteniendo una tupla de valores (cada fila) delscore
diccionario, por defecto a cero si no se encuentra.Tiempos
Dada la variedad de enfoques, pensé que sería interesante comparar algunos de los tiempos.
fuente
score.get
, usaríaitertuples
ozip(*map(df.get, df))
... Para reiterar, este es mi enfoque preferido.df.assign(score=[score.get(t, 0) for t in zip(*map(df.get, df))])
1.0
es el mismo que el hash, por1
lo que las búsquedas de tuplas deberían dar como resultado la misma respuesta. Disculpas @Alexander por tantos comentarios sobre esto, pero solo quiero que las personas voten más por esto porque ... deberían (-:.values
es carozip(*map(df.get, ['col2', 'col1', 'col5']))
u obtener tuplas de una modificación dedf
:zip(*map(df.eq(1).get, df))
Podrías usar map , ya que score es un diccionario:
Salida
Como alternativa, podría utilizar una lista de comprensión:
fuente
Lista de comprensión y mapa:
Salida:
fuente
reindex
O
merge
fuente
Puede ser otra forma estaría usando
.loc[]
:fuente
Solución simple de una línea, uso
get
ytuple
fila-sabio,La solución anterior supone que no hay columnas distintas de las deseadas en orden. Si no, solo use columnas
fuente
score.get
es bueno. Sin embargo, debería preferir una comprensión, en mi opinión. Ver los horarios de @ Alexander .