Pandalar: her grupta eksik değerleri ortalama olarak doldurma


88

Bu basit olmalı, ancak bulduğum en yakın şey şu gönderi: pandalar: Bir grup içindeki eksik değerleri doldurmak ve hala sorunumu çözemiyorum ...

Aşağıdaki veri çerçevesine sahip olduğumu varsayalım

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

ve "NaN" yi her "isim" grubundaki ortalama değerle doldurmak istiyorum, yani

      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

Sonra nereye gideceğimi bilmiyorum:

grouped = df.groupby('name').mean()

Çok teşekkürler.

Yanıtlar:


94

Bir yol kullanmaktır 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

3
Oturup dokümanları okumaya başlarken bunu faydalı buldum. Bu, groupbybölümde ele alınmıştır . Hatırlanması gereken çok şey var, ancak "dönüşüm, orijinal çerçeve gibi dizine alınmasını istediğiniz grup başına işlemler içindir" ve benzeri kurallar alırsınız.
DSM

Ayrıca Wes McKinney kitabına bakın. Şahsen, groupby hakkındaki belgelerin abismal olduğunu düşünüyorum, kitap marjinal olarak daha iyi.
Woody Pride

38
ikiden fazla sütununuz varsa, sütun adını belirttiğinizden emin olun df ["değer"] = df.groupby ("ad"). dönüşüm (lambda x: x.fillna (x.mean ())) ['değer ']
Lauren

16
@Lauren İyi nokta. Performans nedenlerinden ötürü, değer sütunu spesifikasyonunu group-by cümlesinin daha da soluna taşımayı düşünebileceğinizi eklemek isterim. Bu şekilde lambda işlevi, her sütunda değil, yalnızca belirli sütundaki değerler için çağrılır ve sonra sütunu seçer. Bir test yaptı ve iki sütun kullanırken iki kat daha hızlıydı. Ve doğal olarak, atfetmeniz gerekmeyen daha fazla sütun elde edersiniz:df["value"] = df.groupby("name")["value"].transform(lambda x: x.fillna(x.mean()))
André C. Andersen

Bunu iki gündür arıyordum .. Size sadece bir soru. Bunu döngülerle yapmak neden bu kadar zor? Benim durumumda orada iki çoklu indeksleri vardır yani Çünkü Stateve Age_Groupsonra grup vasıtası ile bu grupların değerleri eksik .. Teşekkür (aynı yaş grubundaki aynı durumdan grubunda ortalama ve dolgu eksikleri almak) doldurmaya çalışıyorum
Özkan Serttas

51

fillna+ groupby+ transform+mean

Bu sezgisel görünüyor:

df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))

groupby+ transformSözdizimi orijinal dataframe endeksine groupwise ortalamayı eşler. Bu kabaca @ DSM'nin çözümüne eşdeğerdir , ancak anonim bir lambdaişlev tanımlama ihtiyacını ortadan kaldırır .


25

@DSM'nin doğru cevabı IMO'ya sahip, ancak genellememi ve sorunun optimizasyonunu paylaşmak istiyorum: Gruplandırmaya göre ve birden çok değer sütununa sahip birden çok sütun:

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],
    }
)

... verir ...

  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

Bu genelleştirilmiş durumda biz göre gruplandırmak istiyoruz categoryve nameve sadece üzerinde impute value.

Bu şu şekilde çözülebilir:

df['value'] = df.groupby(['category', 'name'])['value']\
    .transform(lambda x: x.fillna(x.mean()))

Group-by cümlesindeki sütun listesine ve group-by ifadesinden valuehemen sonraki sütunu seçtiğimize dikkat edin . Bu, dönüşümün yalnızca belirli bir sütunda çalıştırılmasını sağlar. Sonuna ekleyebilirsiniz, ancak daha sonra tüm sütunlar için çalıştıracaksınız ve sonunda bir ölçü sütunu hariç hepsini atacaksınız. Standart bir SQL sorgu planlayıcısı bunu optimize edebilirdi, ancak pandalar (0.19.2) bunu yapmıyor gibi görünüyor.

Yaparak veri setini artırarak performans testi ...

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

... bunun kaç tane sütun eklemeniz gerekmediğiyle orantılı olarak hızı artırdığını doğrular:

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

Son bir not olarak, birden fazla sütunu empoze etmek istiyorsanız, ancak hepsini değil, daha da genelleştirebilirsiniz:

df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\
    .transform(lambda x: x.fillna(x.mean()))

Bu harika iş için teşekkür ederim. forDöngüler kullanarak aynı dönüşümü nasıl başarabileceğimi merak ediyorum . Manuel yöntemler bulmaya çalıştığım için hız beni ilgilendirmiyor. Teşekkürler @ AndréC.Andersen
Özkan

12

Bu şekilde yapardım

df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')

1
Bunun biraz farklı bir versiyonudf['value_imputed'] = np.where(df.value.isnull(), df.groupby('group').value.transform('mean'), df.value)
tsando

10

Yukarıdaki cevapların çoğu, eksik değerleri doldurmak için "groupby" ve "transform" kullanmayı içeriyordu.

Ama benim için daha sezgisel olan eksik değerleri doldurmak için "uygula" ile "groupby" kullanmayı tercih ediyorum.

>>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean()))
>>> df.isnull().sum().sum()
    0 

Kısayol: Groupby + Uygula / Lambda + Fillna + Ortalama

Eksik değerleri değiştirmek için birden çok sütuna göre gruplandırmak istiyorsanız bu çözüm yine de işe yarar.

     >>> 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

5

Öne çıkan yüksek dereceli yanıt, yalnızca iki sütunlu Pandalar Veri Çerçevesi için işe yarar. Daha fazla sütun durumunuz varsa bunun yerine şunu kullanın:

df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
    lambda x: x.fillna(x.mean()))

Bu cevap benim için çalıştı, teşekkürler. Ayrıca pandalarda yeni olan herkes için dilimleme notasyonunu kullanarak dizin oluşturabilir df.groupby("continent")['Crude_Birth_rate']... , bunun önerilen covnention olduğuna inanıyorum
Adam Hughes

2
def groupMeanValue(group):
    group['value'] = group['value'].fillna(group['value'].mean())
    return group

dft = df.groupby("name").transform(groupMeanValue)

0
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)

5
Lütfen cevabınız için biraz açıklama yapınız. Google'dan bu sayfaya rastlayan biri neden sizin çözümünüzü diğer 6 cevap yerine kullansın?
divibisan

1
@vino lütfen biraz açıklama ekleyin
Nursnaaz

-1

Ayrıca kullanabilirsiniz "dataframe or table_name".apply(lambda x: x.fillna(x.mean())).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.