KeyError देने वाले len (string) से युक्त एक सशर्त अभिव्यक्ति के आधार पर एक पांडा डेटाफ़्रेम से पंक्तियों को हटाएं


303

मेरे पास एक पांडा डेटाफ़्रेम है और मैं इससे पंक्तियों को हटाना चाहता हूं जहां एक विशेष कॉलम में स्ट्रिंग की लंबाई 2 से अधिक है।

मैं ऐसा करने में सक्षम होने की उम्मीद करता हूं ( इस उत्तर के अनुसार ):

df[(len(df['column name']) < 2)]

लेकिन मुझे सिर्फ त्रुटि मिलती है:

KeyError: u'no item named False'

मैं क्या गलत कर रहा हूं?

(ध्यान दें: मुझे पता है कि मैं उन df.dropna()पंक्तियों से छुटकारा पाने के लिए उपयोग कर सकता हूं जिनमें कोई भी हो NaN, लेकिन मैंने यह नहीं देखा कि कैसे एक सशर्त अभिव्यक्ति के आधार पर पंक्तियों को हटाया जाए।)

जवाबों:


168

जब आप करते हैं तो len(df['column name'])आपको केवल एक संख्या मिल रही है, अर्थात् डेटाफ्रेम में पंक्तियों की संख्या (यानी, कॉलम की लंबाई)। यदि आप lenकॉलम में प्रत्येक तत्व पर लागू करना चाहते हैं , तो उपयोग करें df['column name'].map(len)। इसलिए कोशिश करें

df[df['column name'].map(len) < 2]

3
मैं एक सूची समझ का उपयोग करने का एक तरीका लेकर आया: df[[(len(x) < 2) for x in df['column name']]]लेकिन आपका बहुत अच्छा है। आपकी सहायताके लिए धन्यवाद!
sjs

13
यदि किसी को अधिक जटिल तुलना की आवश्यकता होती है, तो लैम्बडा का उपयोग हमेशा किया जा सकता है। df[df['column name'].map(lambda x: str(x)!=".")]
4lberto

1
किसी कारण से, @ 4lto द्वारा पोस्ट किए गए को छोड़कर किसी भी अन्य विकल्प ने मेरे लिए काम नहीं किया है। मैं हूँ pandas 0.23.4और अजगर 3.6
goelakash

1
मैं एक जोड़ना होगा .copy()अंत में बाद में संपादित करने के लिए इस dataframe (उदाहरण के लिए यदि आप चाहते मामले में, नए स्तंभ बताए उठाएंगे चेतावनी "एक मूल्य एक DataFrame से एक टुकड़ा की एक प्रति पर सेट किया जा करने की कोशिश कर रहा है"।
PlasmaBinturong

806

इस प्रश्न के मूल शीर्षक का सीधा उत्तर देने के लिए "सशर्त अभिव्यक्ति के आधार पर पांडा डेटा से पंक्तियों को कैसे हटाएं" (जो मुझे समझ में आता है कि यह ओपी की समस्या नहीं है, लेकिन इस सवाल पर आने वाले अन्य उपयोगकर्ताओं की मदद कर सकता है) ऐसा करने का एक तरीका है। ड्रॉप विधि:

df = df.drop(some labels)

df = df.drop(df[<some boolean condition>].index)

उदाहरण

उन सभी पंक्तियों को हटाने के लिए जहां कॉलम 'स्कोर' <50 है:

df = df.drop(df[df.score < 50].index)

स्थान संस्करण में (जैसा कि टिप्पणियों में बताया गया है)

df.drop(df[df.score < 50].index, inplace=True)

कई शर्तें

( बूलियन इंडेक्सिंग देखें )

ऑपरेटरों हैं: |के लिए or, &के लिए and, और ~के लिए not। इन्हें कोष्ठकों का उपयोग करके समूहीकृत किया जाना चाहिए।

उन सभी पंक्तियों को हटाने के लिए जहां कॉलम 'स्कोर' <50 और> 20 है

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)


32
मैं सिर्फ यह कहना चाहता हूं कि ड्रॉप फंक्शन, इनप्लेस रिप्लेसमेंट का समर्थन करता है। अर्थात,। आपका समाधान df.drop (df [df.score <50] .index, inplace = True) के समान है। फिर भी "इंडेक्स" ट्रिक नहीं पता था। मेरी बहुत मदद की
Quickbeam2k1

9
केवल यह इंगित करना चाहते हैं कि इस सूचकांक चाल का उपयोग करने से पहले आपको यह सुनिश्चित करने की आवश्यकता है कि आपके सूचकांक मूल्य अद्वितीय हैं (या कॉल reset_index())। मुझे यह पता लगा जब अपने डेटाफ़्रेम से कई पंक्तियों का रास्ता निकल गया।
जे।

3
मैं उन सभी पंक्तियों को कैसे छोड़ सकता / सकती हूँ जहाँ स्तंभ प्रकार str है? मैं केवल सूची स्तंभ प्रकार रखना चाहता हूं। मैंने कोशिश की है, test = df.drop(df[df['col1'].dtype == str].index)लेकिन मुझे वह त्रुटि मिली है जो KeyError: False मैंने भी कोशिश की है df.drop(df[df.col1.dtype == str].index)और df.drop(df[type(df.cleaned_norm_email) == str].index)कुछ भी काम नहीं कर रहा है? क्या कोई सलाह दे सकता है? धन्यवाद! @ उपयोगकर्ता
PyRsquared

1
यह एक पुराना सवाल है लेकिन ... @ जलीय-चुनौती-मछली इस एक की तुलना में बहुत तेज है। ध्यान दें कि आप df[(df.score < 50) & (df.score > 20)]अपने उत्तर के भाग के रूप में गणना करते हैं। यदि आप ऐसा करने के लिए उलट जाते हैं तो df = df[(df.score >= 50) | (df.score <= 20)]आपको अपना उत्तर बहुत तेजी से मिलेगा।
रूबी नुबी

1
@ रॉबीनाउबी - वे एक ही स्थिति नहीं हैं।
नगुई अल

106

आप DataFrameस्वयं के फ़िल्टर किए गए संस्करण को असाइन कर सकते हैं :

df = df[df.score > 50]

इससे तेज है drop:

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test[test.x < 0]
# 54.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test.drop(test[test.x > 0].index, inplace=True)
# 201 ms ± 17.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test.drop(test[test.x > 0].index)
# 194 ms ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

मैं एकाधिक कॉलम का उपयोग करके या स्थिति के लिए कैसे जांच कर सकता हूं?
पीयूष एस। वानारे जुले


9

मैं एक dropमुफ्त विकल्प प्रदान करने के लिए @ उपयोगकर्ता के सामान्य समाधान पर विस्तार करूंगा । यह प्रश्न के शीर्षक (ओपी की समस्या नहीं) के आधार पर यहां निर्देशित लोगों के लिए है

मान लें कि आप नकारात्मक मानों वाली सभी पंक्तियों को हटाना चाहते हैं। एक लाइनर समाधान है: -

df = df[(df > 0).all(axis=1)]

चरण दर चरण स्पष्टीकरण: -

चलो एक 5x5 यादृच्छिक सामान्य वितरण डेटा फ़्रेम उत्पन्न करते हैं

np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,5), columns=list('ABCDE'))
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
1 -0.977278  0.950088 -0.151357 -0.103219  0.410599
2  0.144044  1.454274  0.761038  0.121675  0.443863
3  0.333674  1.494079 -0.205158  0.313068 -0.854096
4 -2.552990  0.653619  0.864436 -0.742165  2.269755

शर्त को नकारात्मक हटा दें। एक बूलियन डीएफ संतोषजनक स्थिति: -

df > 0
      A     B      C      D      E
0   True  True   True   True   True
1  False  True  False  False   True
2   True  True   True   True   True
3   True  True  False   True  False
4  False  True   True  False   True

सभी पंक्तियों के लिए एक बूलियन श्रृंखला हालत को संतुष्ट करती है यदि पंक्ति में कोई भी तत्व विफल हो जाता है तो पंक्ति गलत है

(df > 0).all(axis=1)
0     True
1    False
2     True
3    False
4    False
dtype: bool

अंत में स्थिति के आधार पर डेटा फ्रेम से पंक्तियों को फ़िल्टर करें

df[(df > 0).all(axis=1)]
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
2  0.144044  1.454274  0.761038  0.121675  0.443863

आप प्रदान कर सकते हैं यह वास्तव में करने के लिए df को वापस हटाना बनाम फिल्टर ऊपर किया आईएनजी
df = df[(df > 0).all(axis=1)]

इसे आसानी से NaN s (नॉन न्यूमेरिक एंट्री) वाली पंक्तियों को फ़िल्टर करने के लिए बढ़ाया जा सकता है: -
df = df[(~df.isnull()).all(axis=1)]

इसे ऐसे मामलों के लिए भी सरल बनाया जा सकता है जैसे: उन सभी पंक्तियों को हटा दें जहाँ स्तंभ E ऋणात्मक है

df = df[(df.E>0)]

मैं कुछ प्रोफाइलिंग आंकड़ों के साथ समाप्त करना चाहूंगा कि क्यों @ उपयोगकर्ता का dropसमाधान कच्चे कॉलम आधारित निस्पंदन की तुलना में धीमा है: -

%timeit df_new = df[(df.E>0)]
345 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit dft.drop(dft[dft.E < 0].index, inplace=True)
890 µs ± 94.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

एक स्तंभ मूल रूप से एक है Seriesयानी एक NumPyसरणी यह किसी भी कीमत के बिना अनुक्रमित कर सकते हैं। अंतर्निहित स्मृति संगठन निष्पादन की गति में कैसे निभाता है, इसके लिए इच्छुक लोगों के लिए यहां पंडों की गति बढ़ाने के लिए एक बढ़िया लिंक है :


6

पांडा में आप str.lenअपनी सीमा के साथ कर सकते हैं और इसे फ़िल्टर करने के लिए बूलियन परिणाम का उपयोग कर सकते हैं ।

df[df['column name'].str.len().lt(2)]

3

यदि आप स्तंभ मान पर कुछ जटिल स्थिति के आधार पर डेटा फ़्रेम की पंक्तियों को छोड़ना चाहते हैं, तो ऊपर लिखे तरीके से लिखना जटिल हो सकता है। मेरे पास निम्नलिखित सरल उपाय हैं जो हमेशा काम करते हैं। मान लें कि आप कॉलम को 'शीर्ष लेख' के साथ छोड़ना चाहते हैं, इसलिए पहले उस कॉलम को एक सूची में प्राप्त करें।

text_data = df['name'].tolist()

अब सूची के प्रत्येक तत्व पर कुछ फ़ंक्शन लागू करें और इसे एक पांडा श्रृंखला में रखें:

text_length = pd.Series([func(t) for t in text_data])

मेरे मामले में मैं सिर्फ टोकनों की संख्या प्राप्त करने की कोशिश कर रहा था:

text_length = pd.Series([len(t.split()) for t in text_data])

अब डेटा फ़्रेम में उपरोक्त श्रृंखला के साथ एक अतिरिक्त कॉलम जोड़ें:

df = df.assign(text_length = text_length .values)

अब हम नए कॉलम पर शर्त लगा सकते हैं जैसे:

df = df[df.text_length  >  10]
def pass_filter(df, label, length, pass_type):

    text_data = df[label].tolist()

    text_length = pd.Series([len(t.split()) for t in text_data])

    df = df.assign(text_length = text_length .values)

    if pass_type == 'high':
        df = df[df.text_length  >  length]

    if pass_type == 'low':
        df = df[df.text_length  <  length]

    df = df.drop(columns=['text_length'])

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