Esto debería ser sencillo, pero lo más cercano que he encontrado es esta publicación: pandas: llenando los valores faltantes dentro de un grupo , y todavía no puedo resolver mi problema ...
Supongamos que tengo el siguiente marco de datos
df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C']})
name value
0 A 1
1 A NaN
2 B NaN
3 B 2
4 B 3
5 B 1
6 C 3
7 C NaN
8 C 3
y me gustaría completar "NaN" con el valor medio en cada grupo de "nombre", es decir
name value
0 A 1
1 A 1
2 B 2
3 B 2
4 B 3
5 B 1
6 C 3
7 C 3
8 C 3
No estoy seguro de a dónde ir después:
grouped = df.groupby('name').mean()
Gracias un montón.
python
pandas
pandas-groupby
imputation
fillna
BlueFeet
fuente
fuente
groupby
sección. Hay demasiadas cosas para recordar, pero elige reglas como "la transformación es para operaciones por grupo que desea indexar como el marco original" y así sucesivamente.df["value"] = df.groupby("name")["value"].transform(lambda x: x.fillna(x.mean()))
State
yAge_Group
luego estoy tratando de completar los valores que faltan en esos grupos con medias de grupo (del mismo estado dentro del mismo grupo de edad, tome la media y complete las faltas en el grupo). Graciasfillna
+groupby
+transform
+mean
Esto parece intuitivo:
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))
La sintaxis
groupby
+transform
asigna la media grupal al índice del marco de datos original. Esto es aproximadamente equivalente a la solución de @ DSM , pero evita la necesidad de definir unalambda
función anónima .fuente
@DSM tiene IMO la respuesta correcta, pero me gustaría compartir mi generalización y optimización de la pregunta: Varias columnas para agrupar y tener múltiples columnas de valor:
df = pd.DataFrame( { 'category': ['X', 'X', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y'], 'name': ['A','A', 'B','B','B','B', 'C','C','C'], 'other_value': [10, np.nan, np.nan, 20, 30, 10, 30, np.nan, 30], 'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], } )
... da ...
category name other_value value 0 X A 10.0 1.0 1 X A NaN NaN 2 X B NaN NaN 3 X B 20.0 2.0 4 X B 30.0 3.0 5 X B 10.0 1.0 6 Y C 30.0 3.0 7 Y C NaN NaN 8 Y C 30.0 3.0
En este caso generalizado, nos gustaría agrupar por
category
yname
, e imputar solo envalue
.Esto se puede resolver de la siguiente manera:
df['value'] = df.groupby(['category', 'name'])['value']\ .transform(lambda x: x.fillna(x.mean()))
Observe la lista de columnas en la cláusula group-by, y que seleccionamos la
value
columna justo después de group-by. Esto hace que la transformación solo se ejecute en esa columna en particular. Puede agregarlo al final, pero luego lo ejecutará para todas las columnas solo para descartar todas las columnas de medida menos una al final. Un planificador de consultas SQL estándar podría haber podido optimizar esto, pero pandas (0.19.2) no parece hacer esto.Prueba de rendimiento aumentando el conjunto de datos haciendo ...
big_df = None for _ in range(10000): if big_df is None: big_df = df.copy() else: big_df = pd.concat([big_df, df]) df = big_df
... confirma que esto aumenta la velocidad proporcionalmente a la cantidad de columnas que no tiene que imputar:
import pandas as pd from datetime import datetime def generate_data(): ... t = datetime.now() df = generate_data() df['value'] = df.groupby(['category', 'name'])['value']\ .transform(lambda x: x.fillna(x.mean())) print(datetime.now()-t) # 0:00:00.016012 t = datetime.now() df = generate_data() df["value"] = df.groupby(['category', 'name'])\ .transform(lambda x: x.fillna(x.mean()))['value'] print(datetime.now()-t) # 0:00:00.030022
En una nota final, puede generalizar aún más si desea imputar más de una columna, pero no todas:
df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\ .transform(lambda x: x.fillna(x.mean()))
fuente
for
bucles. La velocidad no es mi preocupación, ya que estoy tratando de encontrar métodos manuales. Gracias @ AndréC.AndersenLo haría de esta manera
df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
fuente
df['value_imputed'] = np.where(df.value.isnull(), df.groupby('group').value.transform('mean'), df.value)
La mayoría de las respuestas anteriores involucraron el uso de "groupby" y "transform" para completar los valores faltantes.
Pero prefiero usar "groupby" con "aplicar" para completar los valores faltantes, lo cual es más intuitivo para mí.
>>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean())) >>> df.isnull().sum().sum() 0
Atajo: Groupby + Aplicar / Lambda + Fillna + Media
Esta solución aún funciona si desea agrupar por varias columnas para reemplazar los valores faltantes.
>>> df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, np.nan,np.nan, 4, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C'],'class':list('ppqqrrsss')}) >>> df value name class 0 1.0 A p 1 NaN A p 2 NaN B q 3 2.0 B q 4 3.0 B r 5 NaN B r 6 NaN C s 7 4.0 C s 8 3.0 C s >>> df['value']=df.groupby(['name','class'])['value'].apply(lambda x:x.fillna(x.mean())) >>> df value name class 0 1.0 A p 1 1.0 A p 2 2.0 B q 3 2.0 B q 4 3.0 B r 5 3.0 B r 6 3.5 C s 7 4.0 C s 8 3.0 C s
fuente
La respuesta destacada de alto rango solo funciona para un marco de datos de pandas con solo dos columnas. Si tiene un caso de más columnas, utilice en su lugar:
df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform( lambda x: x.fillna(x.mean()))
fuente
df.groupby("continent")['Crude_Birth_rate']...
. Creo que esta es la covnention sugeridadef groupMeanValue(group): group['value'] = group['value'].fillna(group['value'].mean()) return group dft = df.groupby("name").transform(groupMeanValue)
fuente
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
fuente
También puede utilizar
"dataframe or table_name".apply(lambda x: x.fillna(x.mean()))
.fuente