पंडों: प्रत्येक समूह में माध्य से लापता मूल्यों को भरना


87

यह सीधा होना चाहिए, लेकिन मुझे जो निकटतम चीज़ मिली है वह है यह पोस्ट: पांडा: एक समूह के भीतर लापता मूल्यों को भरना , और मैं अभी भी अपनी समस्या को हल नहीं कर सकता हूं ...।

मान लीजिए कि मेरे पास निम्नलिखित डेटाफ़्रेम हैं

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

और मैं प्रत्येक "नाम" समूह में माध्य मान के साथ "NaN" भरना चाहता हूँ, अर्थात

      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

मुझे यकीन नहीं है कि इसके बाद कहाँ जाना है:

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

बहुत बहुत धन्यवाद।

जवाबों:


93

उपयोग करने का एक तरीका होगा 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
डॉक्स के माध्यम से बैठकर पढ़ना शुरू करने पर मुझे यह मददगार लगा। यह groupbyखंड में शामिल है । याद रखने के लिए बहुत अधिक सामान है, लेकिन आप नियमों को उठाते हैं जैसे "परिवर्तन प्रति समूह संचालन के लिए है जिसे आप मूल फ्रेम की तरह अनुक्रमित करना चाहते हैं" और इसी तरह।
डीएसएम

वेस मैककिनी पुस्तक भी देखें। व्यक्तिगत रूप से मुझे लगता है कि ग्रुपबी पर डॉक्स अबिज़्मल हैं, पुस्तक थोड़ी बेहतर है।
वुडी प्राइड

38
यदि आपके पास दो से अधिक कॉलम हैं, तो कॉलम नाम df ["value"] = df.groupby ("नाम") निर्दिष्ट करना सुनिश्चित करें। (lambda x: x.fillna (x.mean ())) [value] ']
लॉरेन

16
@ लॉरेन गुड पॉइंट। मैं यह जोड़ना चाहूंगा कि प्रदर्शन कारणों से आप मान-स्तंभ विनिर्देश को आगे बढ़ाकर समूह-समूह खंड पर छोड़ सकते हैं। इस तरह से लैम्ब्डा फ़ंक्शन को केवल उस विशेष कॉलम में मानों के लिए कहा जाता है, और प्रत्येक कॉलम को नहीं और फिर कॉलम को चुना। एक परीक्षण किया और दो कॉलम का उपयोग करते समय यह दोगुना तेज़ था। और स्वाभाविक रूप से आप बेहतर प्रदर्शन प्राप्त करते हैं और अधिक स्तंभ जिन्हें आपको थोपने की आवश्यकता नहीं है:df["value"] = df.groupby("name")["value"].transform(lambda x: x.fillna(x.mean()))
एंड्रे सी। एंडरसन

मैं दो दिनों से इसे खोज रहा हूं .. बस आपके लिए एक सवाल। लूप के साथ ऐसा करना बहुत मुश्किल क्यों है? क्योंकि मेरे मामले में वहाँ दो बहु अनुक्रमित रहे हैं यानी Stateऔर Age_Groupफिर मैं याद आ रही समूह साधनों के साथ उन समूहों में मूल्यों (एक ही उम्र के समूह के भीतर एक ही राज्य से समूह में मतलब और भरने missings लेने के लिए) .. धन्यवाद भरने के लिए कोशिश कर रहा हूँ
ओज़्कान Serttas

51

fillna+ groupby+ transform+mean

यह सहज लगता है:

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

groupby+ transformवाक्य रचना मूल dataframe के सूचकांक को ग्रुपवाइज मतलब मैप करता है। यह लगभग @ DSM के समाधान के बराबर है , लेकिन एक अनाम lambdaफ़ंक्शन को परिभाषित करने की आवश्यकता से बचा जाता है ।


25

@DSM के पास IMO का सही उत्तर है, लेकिन मैं अपने सामान्यीकरण और प्रश्न के अनुकूलन को साझा करना चाहूंगा: कई कॉलम समूह-द्वारा और कई मान स्तंभों के साथ:

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

... देता है ...

  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

इस सामान्यीकृत मामले में हम categoryऔर के द्वारा समूह बनाना चाहते हैं name, और केवल पर थोपना चाहते हैं value

इसे निम्नानुसार हल किया जा सकता है:

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

समूह-दर-खंड में कॉलम सूची पर ध्यान दें, और हम valueसमूह-दर के बाद स्तंभ का चयन करें । यह परिवर्तन केवल उस विशेष स्तंभ पर चलाया जाता है। आप इसे अंत तक जोड़ सकते हैं, लेकिन फिर आप इसे सभी स्तंभों के लिए चलाएंगे, लेकिन अंत में सभी माप स्तंभों को निकाल देंगे। एक मानक SQL क्वेरी प्लानर इसे अनुकूलित करने में सक्षम हो सकता है, लेकिन पांडा (0.19.2) ऐसा करने के लिए प्रतीत नहीं होता है।

डेटासेट बढ़ाकर प्रदर्शन परीक्षण ...

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

... पुष्टि करता है कि इससे गति आनुपातिक बढ़ जाती है कि आपको कितने कॉलम लगाने हैं:

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

अंतिम नोट पर आप आगे भी सामान्यीकरण कर सकते हैं यदि आप एक से अधिक कॉलम लगाना चाहते हैं, लेकिन सभी नहीं:

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

इस महान कार्य के लिए धन्यवाद। मैं सोच रहा हूं कि कैसे मैं forलूप्स का उपयोग करके उसी परिवर्तन को सफल कर सकता हूं । जब से मैं मैनुअल तरीके खोजने की कोशिश कर रहा हूं, स्पीड मेरी चिंता नहीं है। धन्यवाद @ AndréC.Andersen
Ozkan Serttas

12

मैं इसे इस तरह से करूँगा

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

1
इसका थोड़ा अलग संस्करण हैdf['value_imputed'] = np.where(df.value.isnull(), df.groupby('group').value.transform('mean'), df.value)
tsando

9

उपर्युक्त अधिकांश उत्तर "ग्रुपबी" और लापता मूल्यों को भरने के लिए "ट्रांसफ़ॉर्म" का उपयोग करते हैं।

लेकिन मैं उन लापता मूल्यों को भरने के लिए "लागू" के साथ "समूह" का उपयोग करना पसंद करता हूं जो मेरे लिए अधिक सहज हैं।

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

शॉर्टकट: ग्रुपबी + अप्लाई / लैम्ब्डा + फिलना + मीन

यह समाधान अभी भी काम करता है यदि आप लापता मानों को बदलने के लिए कई कॉलमों द्वारा समूह बनाना चाहते हैं।

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

विशेष रुप से उच्च रैंक वाला उत्तर केवल दो कॉलम के साथ एक पांडा डेटाफ्रेम के लिए काम करता है। यदि आपके पास इसके बजाय अधिक स्तंभ केस का उपयोग है:

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

इस जवाब ने मेरे लिए काम किया, धन्यवाद। पांडा के लिए किसी भी नए के लिए, df.groupby("continent")['Crude_Birth_rate']... स्लाइस अंकन का उपयोग करके भी अनुक्रमित कर सकते हैं मेरा मानना ​​है कि यह सुझाया गया covnention है
एडम ह्यूजेस


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

5
कृपया अपने उत्तर की कुछ व्याख्या दें। कोई ऐसा व्यक्ति जो Google से इस पृष्ठ पर ठोकर खाता है, अन्य 6 उत्तरों पर आपके समाधान का उपयोग करे?
देवीबदन

1
@vino कृपया कुछ स्पष्टीकरण जोड़ें
Nursnaaz

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.