clean data in python
Pandas: completando los valores perdidos por media en cada grupo (6)
@DSM tiene IMO la respuesta correcta, pero me gustaría compartir mi generalización y optimización de la pregunta: columnas múltiples para agrupar por y tener columnas de valores múltiples:
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
y name
e imputar solo el value
.
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 seleccione la columna value
justo después del 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 menos una medida al final. Un planificador de consultas SQL estándar podría haber sido capaz de optimizar esto, pero pandas (0.19.2) no parece hacer esto.
Prueba de rendimiento al aumentar el conjunto de datos al hacer ...
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 proporcional 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()))
Esto debería ser sencillo, pero lo más cercano que he encontrado es esta publicación: pandas: llenando los valores perdidos 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 valor medio en cada grupo "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.
Acabo de hacer esto
df.fillna(df.mean(), inplace=True)
Todos los valores perdidos dentro de su DataFrame se llenarán por medio. Si eso es lo que estás buscando. Esto funcionó para mí. Es simple y hace el trabajo.
La respuesta destacada destacada solo funciona para un Dataframe de pandas con solo dos columnas. Si tiene un caso más columnas, use en su lugar:
df[''Crude_Birth_rate''] = df.groupby("continent").Crude_Birth_rate.transform(
lambda x: x.fillna(x.mean()))
Lo haría de esta manera
df.loc[df.value.isnull(), ''value''] = df.groupby(''group'').value.transform(''mean'')
Una forma sería usar la transform
:
>>> df
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
>>> df["value"] = df.groupby("name").transform(lambda x: x.fillna(x.mean()))
>>> df
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
def groupMeanValue(group):
group[''value''] = group[''value''].fillna(group[''value''].mean())
return group
dft = df.groupby("name").transform(groupMeanValue)