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

groupbysecció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()))StateyAge_Groupluego 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+meanEsto parece intuitivo:
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))La sintaxis
groupby+transformasigna 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 unalambdafunció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.0En este caso generalizado, nos gustaría agrupar por
categoryyname, 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
valuecolumna 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.030022En 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
forbucles. 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() 0Atajo: 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 sfuente
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