To powinno być proste, ale najbliższą rzeczą, jaką znalazłem, jest ten post: pandy: Uzupełnianie brakujących wartości w grupie , a nadal nie mogę rozwiązać swojego problemu ....
Załóżmy, że mam następującą ramkę danych
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
i chciałbym wypełnić „NaN” wartością średnią w każdej grupie „name”, tj
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
Nie jestem pewien, dokąd iść:
grouped = df.groupby('name').mean()
Wielkie dzięki.
python
pandas
pandas-groupby
imputation
fillna
BlueFeet
źródło
źródło
groupby
sekcji. Jest zbyt wiele rzeczy do zapamiętania, ale wybierasz reguły takie jak „transformacja dotyczy operacji na grupę, które chcesz indeksować jak oryginalna ramka” i tak dalej.df["value"] = df.groupby("name")["value"].transform(lambda x: x.fillna(x.mean()))
State
AAge_Group
wtedy staram się uzupełnić braki w tych grupach średnimi grupowymi (z tego samego stanu w tej samej grupie wiekowej należy wziąć średnią i wypełnić braki w grupie). Dziękifillna
+groupby
+transform
+mean
Wydaje się to intuicyjne:
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))
groupby
+transform
Składnia mapuje średnią GroupWise do indeksu pierwotnego dataframe. Jest to w przybliżeniu odpowiednik rozwiązania @ DSM , ale pozwala uniknąć konieczności definiowanialambda
funkcji anonimowej .źródło
@DSM ma IMO właściwą odpowiedź, ale chciałbym podzielić się moim uogólnieniem i optymalizacją pytania: Wiele kolumn do grupowania i posiadających wiele kolumn wartości:
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], } )
... daje ...
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
W tym uogólnionym przypadku chcielibyśmy pogrupować według
category
iname
, a imputować tylko wedługvalue
.Można to rozwiązać w następujący sposób:
df['value'] = df.groupby(['category', 'name'])['value']\ .transform(lambda x: x.fillna(x.mean()))
Zwróć uwagę na listę kolumn w klauzuli group-by i że wybieramy
value
kolumnę tuż po funkcji group-by. To sprawia, że transformacja jest uruchamiana tylko w tej konkretnej kolumnie. Możesz dodać go na końcu, ale wtedy uruchomisz go dla wszystkich kolumn tylko po to, aby na końcu wyrzucić wszystkie kolumny miar z wyjątkiem jednej. Standardowy planer zapytań SQL mógł to zoptymalizować, ale wydaje się, że pandy (0.19.2) tego nie robią.Test wydajności poprzez zwiększenie zbioru danych poprzez wykonanie ...
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
... potwierdza, że zwiększa to prędkość proporcjonalnie do liczby kolumn, których nie musisz imputować:
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
Na koniec możesz uogólnić jeszcze bardziej, jeśli chcesz przypisać więcej niż jedną kolumnę, ale nie wszystkie:
df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\ .transform(lambda x: x.fillna(x.mean()))
źródło
for
pętli. Szybkość nie jest moim zmartwieniem, ponieważ próbuję znaleźć metody ręczne. Dzięki @ AndréC.AndersenZrobiłbym to w ten sposób
df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
źródło
df['value_imputed'] = np.where(df.value.isnull(), df.groupby('group').value.transform('mean'), df.value)
Większość z powyższych odpowiedzi dotyczyła użycia „grupowania” i „transformacji” do wypełnienia brakujących wartości.
Ale wolę używać „grupuj” z „zastosuj”, aby uzupełnić brakujące wartości, co jest dla mnie bardziej intuicyjne.
>>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean())) >>> df.isnull().sum().sum() 0
Skrót: Grupuj + Zastosuj / Lambda + Fillna + Średnia
To rozwiązanie nadal działa, jeśli chcesz grupować według wielu kolumn, aby zastąpić brakujące wartości.
>>> 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
źródło
Wyróżniona wysoko sklasyfikowana odpowiedź działa tylko dla pandy Dataframe z tylko dwiema kolumnami. Jeśli masz więcej kolumn, użyj zamiast tego:
df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform( lambda x: x.fillna(x.mean()))
źródło
df.groupby("continent")['Crude_Birth_rate']...
Uważam, że jest to sugerowane porozumieniedef groupMeanValue(group): group['value'] = group['value'].fillna(group['value'].mean()) return group dft = df.groupby("name").transform(groupMeanValue)
źródło
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
źródło
Możesz także użyć
"dataframe or table_name".apply(lambda x: x.fillna(x.mean()))
.źródło