किसी स्तंभ में अवांछित भागों को निकालें


129

मैं DataFrame कॉलम में अवांछित भागों को हटाने के लिए एक कुशल तरीका ढूंढ रहा हूं।

डेटा ऐसा दिखता है:

    time    result
1    09:00   +52A
2    10:00   +62B
3    11:00   +44a
4    12:00   +30b
5    13:00   -110a

मुझे ये डेटा ट्रिम करने की आवश्यकता है:

    time    result
1    09:00   52
2    10:00   62
3    11:00   44
4    12:00   30
5    13:00   110

मैंने कोशिश की .str.lstrip('+-')और। str.rstrip('aAbBcC'), लेकिन एक त्रुटि मिली:

TypeError: wrapper() takes exactly 1 argument (2 given)

किसी भी प्वाइंटर की अत्यधिक सराहना की जाएगी!

जवाबों:


167
data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))

धन्यवाद! यह काम करता है। मैं अभी भी अपने दिमाग को मानचित्र के चारों ओर लपेट रहा हूं (), निश्चित नहीं कि इसका उपयोग कब करना है या नहीं करना है ...
Yannan Wang

मुझे यह देखकर प्रसन्नता हुई कि यह विधि प्रतिस्थापित कार्य के साथ भी काम करती है।
बीके

यदि आप प्रत्येक कॉलम को पुनरावृत्त करते हैं, तो आप इस परिणाम को कैसे लागू करते हैं?
medev21

क्या मैं इस फ़ंक्शन का उपयोग नंबर 12 जैसी संख्या को बदलने के लिए कर सकता हूं? अगर मैं x.lstrip ('12 ') करता हूं तो यह सभी 1 और 2s को निकाल लेता है।
डेव

77

मैं किसी स्तंभ में अवांछित भागों को कैसे निकालूं?

मूल प्रश्न पोस्ट किए जाने के 6 साल बाद, पांडा के पास अब "वेक्टराइज्ड" स्ट्रिंग फ़ंक्शन की एक अच्छी संख्या है जो इन स्ट्रिंग हेरफेर संचालन को सफलतापूर्वक कर सकते हैं।

यह उत्तर इनमें से कुछ स्ट्रिंग फ़ंक्शंस का पता लगाएगा, तेज़ विकल्प सुझाएगा, और अंत में तुलनात्मक समय में जाएगा।


.str.replace

मिलान करने के लिए प्रतिस्थापन / प्रतिमान निर्दिष्ट करें, और इसे प्रतिस्थापित करने के लिए प्रतिस्थापन।

pd.__version__
# '0.24.1'

df    
    time result
1  09:00   +52A
2  10:00   +62B
3  11:00   +44a
4  12:00   +30b
5  13:00  -110a

df['result'] = df['result'].str.replace(r'\D', '')
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

यदि आपको पूर्णांक में परिवर्तित परिणाम की आवश्यकता है, तो आप उपयोग कर सकते हैं Series.astype,

df['result'] = df['result'].str.replace(r'\D', '').astype(int)

df.dtypes
time      object
result     int64
dtype: object

यदि आप dfइन-प्लेस को संशोधित नहीं करना चाहते हैं , तो उपयोग करें DataFrame.assign:

df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged

.str.extract

वह विकल्प जिसे आप रखना चाहते हैं, को निकालने के लिए उपयोगी है।

df['result'] = df['result'].str.extract(r'(\d+)', expand=False)
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

इसके साथ extract, कम से कम एक कैप्चर समूह को निर्दिष्ट करना आवश्यक है। expand=Falseपहले कैप्चर ग्रुप से कैप्चर किए गए आइटम के साथ एक श्रृंखला लौटाएगा।


.str.split तथा .str.get

बंटवारे के काम आपके सभी तार इस सुसंगत संरचना का पालन करते हैं।

# df['result'] = df['result'].str.split(r'\D').str[1]
df['result'] = df['result'].str.split(r'\D').str.get(1)
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

यदि आप एक सामान्य समाधान की तलाश कर रहे हैं तो अनुशंसा न करें।


यदि आप str उपर्युक्त रसीला और पठनीय अभिगम आधारित समाधानों से संतुष्ट हैं , तो आप यहाँ रुक सकते हैं। हालांकि, यदि आप अधिक तेज, अधिक प्रदर्शनशील विकल्पों में रुचि रखते हैं, तो पढ़ते रहें।


अनुकूलन: सूची बोध

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

मेरा लेखन, क्या पांडा के लिए लूप्स वास्तव में खराब हैं? मुझे कब ध्यान देना चाहिए? , अधिक से अधिक विस्तार में चला जाता है।

str.replaceविकल्प का उपयोग कर फिर से लिखा जा सकता हैre.sub

import re

# Pre-compile your regex pattern for more performance.
p = re.compile(r'\D')
df['result'] = [p.sub('', x) for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

str.extractउदाहरण के साथ एक सूची समझ का उपयोग कर फिर से लिखा जा सकता है re.search,

p = re.compile(r'\d+')
df['result'] = [p.search(x)[0] for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

यदि NaN या नो-मैच एक संभावना है, तो आपको कुछ त्रुटि जाँच को शामिल करने के लिए उपरोक्त को फिर से लिखना होगा। मैं एक फ़ंक्शन का उपयोग करके ऐसा करता हूं।

def try_extract(pattern, string):
    try:
        m = pattern.search(string)
        return m.group(0)
    except (TypeError, ValueError, AttributeError):
        return np.nan

p = re.compile(r'\d+')
df['result'] = [try_extract(p, x) for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

सूची संकलन का उपयोग करके हम @ eumiro's और @ MonkeyButter के उत्तरों को फिर से लिख सकते हैं:

df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]

तथा,

df['result'] = [x[1:-1] for x in df['result']]

NaNs आदि को संभालने के लिए समान नियम लागू होते हैं।


प्रदर्शन तुलना

यहाँ छवि विवरण दर्ज करें

परफ्लोट का उपयोग करके उत्पन्न रेखांकन । पूर्ण कोड सूची, आपके संदर्भ के लिए। प्रासंगिक कार्य नीचे सूचीबद्ध हैं।

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

कार्य

def eumiro(df):
    return df.assign(
        result=df['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC')))

def coder375(df):
    return df.assign(
        result=df['result'].replace(r'\D', r'', regex=True))

def monkeybutter(df):
    return df.assign(result=df['result'].map(lambda x: x[1:-1]))

def wes(df):
    return df.assign(result=df['result'].str.lstrip('+-').str.rstrip('aAbBcC'))

def cs1(df):
    return df.assign(result=df['result'].str.replace(r'\D', ''))

def cs2_ted(df):
    # `str.extract` based solution, similar to @Ted Petrou's. so timing together.
    return df.assign(result=df['result'].str.extract(r'(\d+)', expand=False))

def cs1_listcomp(df):
    return df.assign(result=[p1.sub('', x) for x in df['result']])

def cs2_listcomp(df):
    return df.assign(result=[p2.search(x)[0] for x in df['result']])

def cs_eumiro_listcomp(df):
    return df.assign(
        result=[x.lstrip('+-').rstrip('aAbBcC') for x in df['result']])

def cs_mb_listcomp(df):
    return df.assign(result=[x[1:-1] for x in df['result']])

सेटिंगविटचोपाइवरिंग से बचने के लिए कोई भी हल:Try using .loc[row_indexer,col_indexer] = value instead
PV8

@ PV8 आपके कोड के बारे में निश्चित नहीं है, लेकिन इसे देखें: stackoverflow.com/questions/20625582/…
cs95

किसी के लिए जो मेरे जैसे REGEX में नया है, \ D यहाँ से [^ \ d] (कुछ भी नहीं है जो एक अंक) है । तो हम मूल रूप से स्ट्रिंग में सभी गैर-अंकों को कुछ नहीं के साथ बदल रहे हैं।
ऋषि लछमीपसर

56

मैं पंडों की जगह फंक्शन का उपयोग कर सकता हूँ, आप रीगेक्स का उपयोग कर सकते हैं। नीचे मैं किसी भी गैर-अंकीय वर्णों को हटाने के लिए regex \ D का उपयोग कर रहा हूं, लेकिन जाहिर है कि आप regex के साथ काफी रचनात्मक हो सकते हैं।

data['result'].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')

मैंने यह कोशिश की, और यह काम नहीं करता है। मैं सोच रहा था कि यह केवल तब काम करता है जब आप केवल एक स्ट्रिंग को प्रतिस्थापित करने के बजाय एक संपूर्ण स्ट्रिंग को बदलना चाहते हैं।
bgenchel

@bgenchel - मैंने pd.Series में स्ट्रिंग के भाग को बदलने के लिए इस विधि का उपयोग किया है df.loc[:, 'column_a'].replace(regex=True, to_replace="my_prefix", value="new_prefix"):। यह "my_prefixaaa" जैसे एक स्ट्रिंग को "new_prefixaaa" में बदल देगा।
याकूब २०'१

R in_replace = r '\ D' में क्या करता है?
लुका गुआरो

अजगर के डॉक्स से @LucaGuarro: "आर प्रीफिक्स, शाब्दिक रूप से एक कच्ची स्ट्रिंग शाब्दिक बना रही है, इस उदाहरण में इसकी आवश्यकता है क्योंकि एक सामान्य" पका हुआ "स्ट्रिंग शाब्दिक में से बचने के क्रम में पायथन द्वारा मान्यता प्राप्त नहीं है, जैसा कि नियमित अभिव्यक्ति के विपरीत है, अब। एक DeprecationWarning में परिणाम और अंततः एक SyntaxError बन जाएगा। "
कोडर 375

35

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

अंतिम चरित्र:

data['result'] = data['result'].map(lambda x: str(x)[:-1])

पहले दो वर्ण:

data['result'] = data['result'].map(lambda x: str(x)[2:])

मुझे 8 वर्णों (सहित (।), ()) () सहित भू-निर्देशांक ट्रिम करने की आवश्यकता है और अगर वे 8 से कम हैं तो मुझे सभी निर्देशांक 8 वर्ण बनाने के लिए अंत में '0' सम्मिलित करने की आवश्यकता है। ऐसा करने का सरल तरीका क्या है?
Sitz Blogz

मुझे आपकी समस्या पूरी तरह से समझ में नहीं आती है, लेकिन आपको "{0: .8f}" जैसे प्रारूप में लैम्ब्डा फ़ंक्शन को बदलने की आवश्यकता हो सकती है। प्रारूप (x)
prl900

आपके उत्तर के लिए बहुत धन्यवाद। सरल शब्दों में मेरे पास जियो निर्देशांक के साथ डेटाफ्रेम है - दो कॉलम के रूप में अक्षांश और देशांतर। वर्णों की लंबाई 8 वर्णों से अधिक है और मैं केवल 8 वर्णों को पहले से शुरू कर रहा था जिसमें (-) और () भी शामिल होना चाहिए।
रिट्ज ब्लॉग्ज़

18

यहाँ एक बग है: वर्तमान में तर्क पारित नहीं कर सकते हैं str.lstripऔर str.rstrip:

http://github.com/pydata/pandas/issues/2411

संपादित करें: 2012-12-07 यह अब देव शाखा पर काम करता है:

In [8]: df['result'].str.lstrip('+-').str.rstrip('aAbBcC')
Out[8]: 
1     52
2     62
3     44
4     30
5    110
Name: result

11

एक बहुत ही सरल विधि extractसभी अंकों को चुनने के लिए विधि का उपयोग करना होगा । बस इसे नियमित अभिव्यक्ति प्रदान करें '\d+'जो किसी भी संख्या के अंकों को निकालता है।

df['result'] = df.result.str.extract(r'(\d+)', expand=True).astype(int)
df

    time  result
1  09:00      52
2  10:00      62
3  11:00      44
4  12:00      30
5  13:00     110

7

मैं अक्सर इन प्रकार के कार्यों के लिए सूची समझ का उपयोग करता हूं क्योंकि वे अक्सर तेज होते हैं।

इस तरह की चीजें करने के लिए विभिन्न तरीकों के बीच प्रदर्शन में बड़े अंतर हो सकते हैं (जैसे कि डेटाफ़्रेम के भीतर एक श्रृंखला के प्रत्येक तत्व को संशोधित करना)। अक्सर एक सूची की समझ सबसे तेज़ हो सकती है - इस कार्य के लिए नीचे कोड रेस देखें:

import pandas as pd
#Map
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))
10000 loops, best of 3: 187 µs per loop
#List comprehension
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in data['result']]
10000 loops, best of 3: 117 µs per loop
#.str
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = data['result'].str.lstrip('+-').str.rstrip('aAbBcC')
1000 loops, best of 3: 336 µs per loop

4

मान लीजिए कि आपका DF उन अतिरिक्त वर्णों के बीच की संख्या में है। अंतिम प्रविष्टि।

  result   time
0   +52A  09:00
1   +62B  10:00
2   +44a  11:00
3   +30b  12:00
4  -110a  13:00
5   3+b0  14:00

आप न केवल शुरुआत और अंत से बल्कि बीच से भी पात्रों को हटाने के लिए str.replace की कोशिश कर सकते हैं।

DF['result'] = DF['result'].str.replace('\+|a|b|\-|A|B', '')

आउटपुट:

  result   time
0     52  09:00
1     62  10:00
2     44  11:00
3     30  12:00
4    110  13:00
5     30  14:00

0

इसे नियमित अभिव्यक्ति का उपयोग करके देखें:

import re
data['result'] = data['result'].map(lambda x: re.sub('[-+A-Za-z]',x)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.