पांडा NaB (लापता) मूल्यों के साथ GroupBy कॉलम


147

मेरे पास स्तंभों में कई लापता मानों के साथ एक डेटाफ़्रेम है, जिसे मैं ग्रुपबी करना चाहता हूं:

import pandas as pd
import numpy as np
df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})

In [4]: df.groupby('b').groups
Out[4]: {'4': [0], '6': [2]}

देखें कि पंडों ने NaN लक्ष्य मानों के साथ पंक्तियों को गिरा दिया है। (मैं इन पंक्तियों को शामिल करना चाहता हूं!)

चूँकि मुझे ऐसे कई ऑपरेशनों की आवश्यकता है (कई कॉलोनों में लापता मान हैं), और सिर्फ मध्यस्थों (आमतौर पर यादृच्छिक वन) की तुलना में अधिक जटिल कार्यों का उपयोग करते हैं, मैं कोड के बहुत जटिल टुकड़ों को लिखने से बचना चाहता हूं।

कोई सुझाव? क्या मुझे इसके लिए एक फ़ंक्शन लिखना चाहिए या क्या एक सरल समाधान है?


1
@PhillipCloud मैंने इस प्रश्न को संपादित किया है जिसमें जेफ़ की पंडों को बढ़ाने से संबंधित सिर्फ एक प्रश्न शामिल है, जो वास्तविक रूप से काफी अच्छा है ।
एंडी हेडन

1
समूहों में NaN को शामिल (और प्रचारित) करने में सक्षम नहीं होना काफी उग्र है। आर का हवाला देते हुए आश्वस्त नहीं है, क्योंकि यह व्यवहार बहुत सी अन्य चीजों के अनुरूप नहीं है। वैसे भी, डमी हैक भी बहुत बुरा है। हालाँकि, एक समूह के आकार (NaNs शामिल हैं) और एक समूह की संख्या (NaNs को अनदेखा करता है) यदि NaN हैं तो अलग-अलग होंगे। dfgrouped = df.groupby (['b')। a.agg (['sum', 'size', 'count']) dfgrouped ['sum'] [dfgrouped [आकार]]! = dfgrouped ['count] ']] = कोई नहीं
ब्रायन प्रेस्लोप्स्की

क्या आप संक्षेप में बता सकते हैं कि आप विशेष रूप से क्या हासिल करने की कोशिश कर रहे हैं? यानी हम एक आउटपुट देखते हैं, लेकिन "वांछित" आउटपुट क्या है?
सीए

2
पांडा 1.1 के साथ आप जल्द ही अपना वांछित परिणाम प्राप्त करने dropna=Falseमें सक्षम होंगे groupby()अधिक जानकारी
CS95

जवाबों:


130

यह डॉक्स के गुम डेटा खंड में उल्लिखित है :

GroupBy में NA समूहों को स्वचालित रूप से बाहर रखा गया है। उदाहरण के लिए, यह व्यवहार R के अनुरूप है।

समूह में करने से पहले एक प्लेसहोल्डर का उपयोग करना एक समाधान है (उदाहरण -1):

In [11]: df.fillna(-1)
Out[11]: 
   a   b
0  1   4
1  2  -1
2  3   6

In [12]: df.fillna(-1).groupby('b').sum()
Out[12]: 
    a
b    
-1  2
4   1
6   3

उस ने कहा, यह बहुत भयानक हैक लगता है ... शायद NaN को ग्रुपबी में शामिल करने का एक विकल्प होना चाहिए ( इस गीथूब मुद्दे को देखें - जो समान प्लेसहोल्डर हैक का उपयोग करता है)।


4
यह एक तार्किक लेकिन एक प्रकार का मज़ेदार समाधान है जो मैंने पहले सोचा है, पंडों ने खाली लोगों से NaN फ़ील्ड बनाया है, और हमें उन्हें वापस बदलना होगा। यही कारण है कि मैं अन्य समाधानों की तलाश में हूं जैसे कि एसक्यूएल सर्वर चलाना और वहां से तालिकाओं को क्वेरी करना (थोड़ा बहुत जटिल दिखता है), या पंडों के बावजूद किसी अन्य पुस्तकालय को देखना, या अपना खुद का उपयोग करना (जो मुझे चाहिए) छुटकारा पाना)। Thx
गयुला सेमुएल कार्ली

@ GyulaSámuelKarli मेरे लिए यह एक छोटा सा बग (ऊपर बग्रेपोर्ट देखें) लगता है, और मेरा समाधान एक समाधान है। मुझे यह अजीब लगता है कि आप पूरी लाइब्रेरी को लिखते हैं।
एंडी हेडन

1
मैं पंडों को लिखना नहीं चाहता, बस उस उपकरण की तलाश करता हूं जो मेरे अनुरोधों को सबसे अधिक फिट करता है।
गियुला सेमुएल करली

1
नीचे मेरे उत्तर पर एक नज़र डालें, मेरा मानना ​​है कि मुझे बहुत अच्छा (क्लीनर, और शायद तेज) समाधान मिला है। stackoverflow.com/a/43375020/408853
ca

4
नहीं, यह R. df%>% group_by के अनुरूप नहीं है। NA सारांश भी एक चेतावनी के साथ देगा जिसे fct_explicit_na के माध्यम से समूहीकरण कॉलम को पास करने से रोका जा सकता है और फिर एक (गुम) स्तर बनाया जाता है।
केयरिंग केयर

40

प्राचीन विषय, अगर कोई अभी भी इस पर ठोकर खाता है - एक और समाधान समूह से पहले स्ट्रिंग में .astype (str) के माध्यम से परिवर्तित करना है। यह NaN का संरक्षण करेगा।

in:
df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})
df['b'] = df['b'].astype(str)
df.groupby(['b']).sum()
out:
    a
b   
4   1
6   3
nan 2

@ K3 --- rnc: अपने लिंक पर टिप्पणी देखें - आपके लिंक में पोस्ट के लेखक ने कुछ गलत किया है।
थॉमस

@ थोमस, हां, जैसा कि ऊपर दिए गए उदाहरण में है। कृपया संपादित करें यदि आप उदाहरण को सुरक्षित (और तुच्छ के रूप में) बना सकते हैं।
K3 --- rnc

sumकी aस्ट्रिंग संयोजन यहाँ, नहीं एक अंकीय योग है। यह केवल "काम करता है" क्योंकि 'बी' में अलग-अलग प्रविष्टियाँ शामिल थीं। आपको सांख्यिक होने के लिए 'a' की आवश्यकता है और स्ट्रिंग के लिए 'b'
BallpointBen

28

पांडा> = 1.1

पंडों 1.1 से आप इस व्यवहार पर बेहतर नियंत्रण रखते हैं, एनए मूल्यों को अब ग्रॉपर का उपयोग करने की अनुमति हैdropna=False :

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

# Example from the docs
df

   a    b  c
0  1  2.0  3
1  1  NaN  4
2  2  1.0  3
3  1  2.0  2

# without NA (the default)
df.groupby('b').sum()

     a  c
b        
1.0  2  3
2.0  2  5
# with NA
df.groupby('b', dropna=False).sum()

     a  c
b        
1.0  2  3
2.0  2  5
NaN  1  4

4
उम्मीद है कि यह उत्तर शीर्ष पर एक क्रमिक मार्च बनाता है। यह सही तरीका है।
18

मुझे नहीं लगता कि 1.1 अभी तक जारी किया गया है। कोंडा और पाइप पर जांच की गई और संस्करण अभी भी 1.0.4 हैं
sammywemmy

1
@sammywemmy हां, अब यह केवल एक विकास के माहौल के अंदर चलाया जा सकता है । जब पुराने एसओ पदों पर नई सुविधाओं की शुरुआत करने की बात आती है तो मुझे हेडस्टार्ट करना पसंद है। ;-)
सीएस 95

9

मैं एम। Kiewisch के लिए एक टिप्पणी जोड़ने में सक्षम नहीं हूं क्योंकि मेरे पास पर्याप्त प्रतिष्ठा अंक नहीं हैं (केवल 41 हैं लेकिन टिप्पणी करने के लिए 50 से अधिक की आवश्यकता है)।

वैसे भी, केवल यह बताना चाहते हैं कि एम। Kiewisch समाधान काम नहीं करता है और अधिक ट्विकिंग की आवश्यकता हो सकती है। उदाहरण के लिए विचार करें

>>> df = pd.DataFrame({'a': [1, 2, 3, 5], 'b': [4, np.NaN, 6, 4]})
>>> df
   a    b
0  1  4.0
1  2  NaN
2  3  6.0
3  5  4.0
>>> df.groupby(['b']).sum()
     a
b
4.0  6
6.0  3
>>> df.astype(str).groupby(['b']).sum()
      a
b
4.0  15
6.0   3
nan   2

जो दर्शाता है कि समूह b = 4.0 के लिए, संबंधित मान 6. के बजाय 15 है। यहां यह संख्याओं के रूप में जोड़ने के बजाय केवल 1 और 5 को समवर्ती माना जाता है।


12
ऐसा इसलिए है क्योंकि आपने केवल bस्तंभ के बजाय पूरे DF को str में परिवर्तित कर दिया है
Korem

ध्यान दें कि यह उल्लेखित उत्तर में अब तय किया गया है।
शैडो -

1
नया उपाय बेहतर है लेकिन अभी भी सुरक्षित नहीं है, मेरी राय में। एक मामले पर विचार करें जहां स्तंभ 'बी' में प्रविष्टियों में से एक स्ट्रिंग np.NaN के समान है। फिर उन चीजों को एक साथ जोड़ दिया जाता है। df = pd.DataFrame ({'a': [1, 2, 3, 5, 6], 'b': ['foo', np.NaN, 'bar', 'foo', 'nan']]) ; df ['b'] = df ['b']। astype (str); df.groupby (['b'])। राशि ()
कामराजु कुसुमची

6

एंडी हेडन के समाधान के लिए एक छोटा बिंदु - यह काम नहीं करता है (अब?) क्योंकि np.nan == np.nanपैदावार False, इसलिए replaceफ़ंक्शन वास्तव में कुछ भी नहीं करता है।

मेरे लिए क्या काम था:

df['b'] = df['b'].apply(lambda x: x if not np.isnan(x) else -1)

(कम से कम पंडों के लिए यह व्यवहार 0.19.2 है। इसे अलग उत्तर के रूप में जोड़ने के लिए क्षमा करें, मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है।)


12
भी है df['b'].fillna(-1)
K3 --- rnc

6

इस प्रकार प्रदान किए गए सभी उत्तर संभावित खतरनाक व्यवहार का परिणाम देते हैं क्योंकि यह संभव है कि आप एक डमी मूल्य का चयन करें जो वास्तव में डेटासेट का हिस्सा है। जब आप कई विशेषताओं के साथ समूह बनाते हैं तो इसकी संभावना बढ़ जाती है। सीधे शब्दों में कहें, दृष्टिकोण हमेशा अच्छी तरह से सामान्य नहीं होता है।

एक कम हैकी हल है pd.drop_duplicates () का उपयोग करके प्रत्येक व्यक्ति की अपनी आईडी के साथ मूल्य संयोजन का एक अनूठा सूचकांक बनाने के लिए, और फिर उस आईडी पर समूह बनाएं। यह अधिक क्रिया है लेकिन काम पूरा कर लेता है:

def safe_groupby(df, group_cols, agg_dict):
    # set name of group col to unique value
    group_id = 'group_id'
    while group_id in df.columns:
        group_id += 'x'
    # get final order of columns
    agg_col_order = (group_cols + list(agg_dict.keys()))
    # create unique index of grouped values
    group_idx = df[group_cols].drop_duplicates()
    group_idx[group_id] = np.arange(group_idx.shape[0])
    # merge unique index on dataframe
    df = df.merge(group_idx, on=group_cols)
    # group dataframe on group id and aggregate values
    df_agg = df.groupby(group_id, as_index=True)\
               .agg(agg_dict)
    # merge grouped value index to results of aggregation
    df_agg = group_idx.set_index(group_id).join(df_agg)
    # rename index
    df_agg.index.name = None
    # return reordered columns
    return df_agg[agg_col_order]

ध्यान दें कि आप अब बस निम्नलिखित कर सकते हैं:

data_block = [np.tile([None, 'A'], 3),
              np.repeat(['B', 'C'], 3),
              [1] * (2 * 3)]

col_names = ['col_a', 'col_b', 'value']

test_df = pd.DataFrame(data_block, index=col_names).T

grouped_df = safe_groupby(test_df, ['col_a', 'col_b'],
                          OrderedDict([('value', 'sum')]))

यह डमी मूल्य के रूप में गलत डेटा को अधिलेखित करने वाले वास्तविक डेटा के बारे में चिंता किए बिना सफल परिणाम लौटाएगा।


यह सामान्य मामले के लिए सबसे अच्छा समाधान है, लेकिन उन मामलों में जहां मुझे एक अमान्य स्ट्रिंग / संख्या के बारे में पता है जिसका मैं इसके बजाय उपयोग कर सकता हूं, मैं शायद एंडी हेडन के जवाब के साथ जा रहा हूं ... मुझे उम्मीद है कि पांडा जल्द ही इस व्यवहार को ठीक कर देंगे।
सारा मेसर

4

मैंने इसका उत्तर पहले ही दे दिया था, लेकिन कुछ कारण उत्तर को टिप्पणी में बदल दिया गया। फिर भी, यह सबसे कारगर उपाय है:

समूहों में NaN को शामिल करना (और प्रचार करना) सक्षम नहीं होना काफी कष्टप्रद है। आर का हवाला देते हुए आश्वस्त नहीं है, क्योंकि यह व्यवहार बहुत सी अन्य चीजों के अनुरूप नहीं है। वैसे भी, डमी हैक भी बहुत बुरा है। हालाँकि, एक समूह के आकार (NaNs शामिल हैं) और एक समूह की गणना (NaNs को अनदेखा करता है) यदि NaN हैं तो अलग-अलग होंगे।

dfgrouped = df.groupby(['b']).a.agg(['sum','size','count'])

dfgrouped['sum'][dfgrouped['size']!=dfgrouped['count']] = None

जब ये भिन्न होते हैं, तो आप उस समूह के लिए एकत्रीकरण फ़ंक्शन के परिणाम के लिए मान को वापस सेट कर सकते हैं।


1
यह मेरे लिए सुपर सहायक था लेकिन यह मूल एक की तुलना में थोड़ा अलग सवाल का जवाब देता है। IIUC, आपका समाधान समन में NaNs का प्रचार करता है, लेकिन "b" कॉलम में NaN आइटम अभी भी पंक्तियों के रूप में गिराए जाते हैं।
एंड्रयू

0

एनाकोंडा में पंडों को स्थापित 1.1

मैं cs95 के उत्तर पर टिप्पणी करने में सक्षम नहीं हूं, लेकिन उन्होंने मुझे इस मुद्दे को हल करने में मदद की।

मैंने पंडों को 1.1 स्थापित करने की कोशिश की, लेकिन यह उनके कोड का उपयोग करने में विफल रहा, इसलिए मैं googled और स्थापित करने में सक्षम था।

मैं पहले व्यवस्थापक के रूप में एनाकोंडा प्रॉम्प्ट चलाता हूं और निम्नलिखित कोड पेस्ट करता हूं :

pip install pandas==1.1.0rc0

इसके बाद उपयोग शामिल करें dropna = False

लिंक: https://lbooks.io/pypi/pandas


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