एक श्रृंखला / डेटाफ्रेम कॉलम के पंडों की सशर्त रचना


314

मेरे पास नीचे की तर्ज पर एक डेटाफ्रेम है:

    Type       Set
1    A          Z
2    B          Z           
3    B          X
4    C          Y

मैं डेटाफ़्रेम (= रिकॉर्ड्स / पंक्तियों की समान संख्या) के समान लंबाई के डेटाफ़्रेम (या एक श्रृंखला) को जोड़ने के लिए एक और कॉलम जोड़ना चाहता हूं जो अगर सेट = अन्यथा हो तो एक रंग हरा सेट करता है। ।

ऐसा करने का सबसे अच्छा तरीका क्या है?

जवाबों:


711

यदि आपके पास चयन करने के लिए केवल दो विकल्प हैं:

df['color'] = np.where(df['Set']=='Z', 'green', 'red')

उदाहरण के लिए,

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
df['color'] = np.where(df['Set']=='Z', 'green', 'red')
print(df)

पैदावार

  Set Type  color
0   Z    A  green
1   Z    B  green
2   X    B    red
3   Y    C    red

यदि आपके पास दो से अधिक स्थितियां हैं तो उपयोग करेंnp.select । उदाहरण के लिए, यदि आप बनना चाहते colorहैं

  • yellow कब (df['Set'] == 'Z') & (df['Type'] == 'A')
  • नहीं blueतो कब(df['Set'] == 'Z') & (df['Type'] == 'B')
  • नहीं purpleतो कब(df['Type'] == 'B')
  • अन्यथा black,

तो उपयोग करें

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
conditions = [
    (df['Set'] == 'Z') & (df['Type'] == 'A'),
    (df['Set'] == 'Z') & (df['Type'] == 'B'),
    (df['Type'] == 'B')]
choices = ['yellow', 'blue', 'purple']
df['color'] = np.select(conditions, choices, default='black')
print(df)

कौन सी पैदावार

  Set Type   color
0   Z    A  yellow
1   Z    B    blue
2   X    B  purple
3   Y    C   black

1
अगर मैं दो शर्तों के अंदर काम करता हूं, तो मैं काम नहीं करता हूं
अमोल शर्मा

2
df ['color'] = list (np.where (df ['सेट'] == 'Z', 'हरा', 'लाल')) पांडा की चेतावनी को दबा देगा: एक मूल्य एक प्रति पर सेट होने की कोशिश कर रहा है एक DataFrame से एक टुकड़ा। .Loc [row_indexer, col_indexer] = मान के बजाय उपयोग करने का प्रयास करें
denson

3
'ग्रीन' और 'रेड' को कॉलम अंकगणित से भी बदला जा सकता है। उदाहरण के लिए ,df['foo'] = np.where(df['Set']=='Z', df['Set'], df['Type'].shift(1))
अलेजांद्रो

क्या np.where एक नया स्तंभ बनाता है? मैंने इस कोड का इस्तेमाल किया और जब मैं df.color.head () करता हूं: मुझे 'numpy.ndarray' ऑब्जेक्ट में कोई विशेषता नहीं 'हेड' है
vvv

3
यह शर्म की बात है कि मैं इस कई बार upvote नहीं कर सकता। एक upvote पर्याप्त नहीं लगता है।
हार्पर

120

सशर्त रूप से एक और स्तंभ बनाने के लिए सूची समझ एक और तरीका है। यदि आप कॉलम में ऑब्जेक्ट dtypes के साथ काम कर रहे हैं, जैसे आपके उदाहरण में, सूची की समझ आमतौर पर अधिकांश अन्य तरीकों से बेहतर होती है।

उदाहरण सूची समझ:

df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]

% समय परीक्षण:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
%timeit df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
%timeit df['color'] = np.where(df['Set']=='Z', 'green', 'red')
%timeit df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

1000 loops, best of 3: 239 µs per loop
1000 loops, best of 3: 523 µs per loop
1000 loops, best of 3: 263 µs per loop

4
ध्यान दें कि, बहुत बड़े डेटाफ़्रेम (थिंक pd.DataFrame({'Type':list('ABBC')*100000, 'Set':list('ZZXY')*100000})-साइज़), numpy.whereआउटस्पेस के साथ map, लेकिन लिस्ट कॉम्प्रिहेंशन किंग (लगभग 50% तेज़ी से numpy.where) है।
अश्वेत

3
यदि सूची को कई स्तंभों से जानकारी की आवश्यकता है, तो सूची बोध विधि का उपयोग किया जा सकता है? मैं कुछ इस तरह की तलाश कर रहा हूं (यह काम नहीं करता है):df['color'] = ['red' if (x['Set'] == 'Z') & (x['Type'] == 'B') else 'green' for x in df]
मप्पी

2
डेटाफ़्रेम में पुनरावृत्तियों को जोड़ें, फिर आप पंक्ति के माध्यम से कई स्तंभों तक पहुँच सकते हैं: ['लाल' 'इंडेक्स के लिए, df.iterrows () में पंक्ति
cheekybastard

1
ध्यान दें कि यह अच्छा समाधान काम नहीं करेगा यदि आपको डेटा फ़्रेम में किसी अन्य श्रृंखला से प्रतिस्थापन मान लेने की आवश्यकता है, जैसे किdf['color_type'] = np.where(df['Set']=='Z', 'green', df['Type'])
पॉल रूजियक्स

@cheekybastard या नहीं, क्योंकि .iterrows()यह बेहद सुस्त है और पुनरावृत्ति करते समय DataFrame को संशोधित नहीं किया जाना चाहिए।
एएमसी

21

दूसरा तरीका जिसमें यह हासिल किया जा सकता है

df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

अच्छा दृष्टिकोण, यह तेजी से दक्षता (बड़े डेटासेट में) के लिए याद किया जा सकता है, हालांकि इसके लिए एक अतिरिक्त कदम की आवश्यकता होगी।
याकोव ब्रेसलर

21

इस बिल्ली की त्वचा पर एक और तरीका है, सूची में कुंजियों पर नए मूल्यों को मैप करने के लिए एक शब्दकोश का उपयोग करते हुए:

def map_values(row, values_dict):
    return values_dict[row]

values_dict = {'A': 1, 'B': 2, 'C': 3, 'D': 4}

df = pd.DataFrame({'INDICATOR': ['A', 'B', 'C', 'D'], 'VALUE': [10, 9, 8, 7]})

df['NEW_VALUE'] = df['INDICATOR'].apply(map_values, args = (values_dict,))

यह कैसा दिख रहा है:

df
Out[2]: 
  INDICATOR  VALUE  NEW_VALUE
0         A     10          1
1         B      9          2
2         C      8          3
3         D      7          4

यह दृष्टिकोण बहुत शक्तिशाली हो सकता है जब आपके पास ifelseबनाने के लिए कई- प्रकार के कथन (यानी कई अद्वितीय मान हों)।

और निश्चित रूप से आप हमेशा ऐसा कर सकते हैं:

df['NEW_VALUE'] = df['INDICATOR'].map(values_dict)

लेकिन वह तरीका applyमेरी मशीन पर ऊपर से दृष्टिकोण जितना धीमा है, तीन गुना से अधिक है ।

और आप यह भी कर सकते हैं, का उपयोग कर dict.get:

df['NEW_VALUE'] = [values_dict.get(v, None) for v in df['INDICATOR']]

मुझे यह उत्तर पसंद है क्योंकि यह दिखाता है कि मूल्यों के कई प्रतिस्थापन कैसे किए जाते हैं
मोनिका हेडनक

लेकिन वह तरीका मेरी मशीन पर ऊपर से लागू दृष्टिकोण जितना धीमा है, तीन गुना से अधिक है। आपने इन्हें कैसे बेंचमार्क किया? मेरे त्वरित माप से, .map()समाधान ~ की तुलना में 10 गुना तेज है .apply()
एएमसी

अपडेट: 100,000,000 पंक्तियों पर, 52 स्ट्रिंग मान, .apply()47 सेकंड लेता है, बनाम केवल 5.91 सेकंड के लिए .map()
एएमसी

19

निम्नलिखित धीमी गति से दृष्टिकोण का समय समाप्त हो रहा है यहाँ , लेकिन हम एक से अधिक स्तंभ की सामग्री के आधार पर अतिरिक्त स्तंभ की गणना कर सकते हैं और अधिक से अधिक दो मानों अतिरिक्त स्तंभ के लिए गणना की जा सकती।

केवल "सेट" कॉलम का उपयोग करके सरल उदाहरण:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

अधिक रंग और अधिक स्तंभों को ध्यान में रखते हुए उदाहरण:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    elif row["Type"] == "C":
        return "blue"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C   blue

संपादित करें (21/06/2019): प्लाईडेटा का उपयोग करना

इस तरह की चीजों को करने के लिए प्लाईडेटा का उपयोग करना भी संभव है (यह उपयोग करने की तुलना में धीमा भी लगता है assignऔर apply, हालांकि)।

from plydata import define, if_else

सरल if_else:

df = define(df, color=if_else('Set=="Z"', '"red"', '"green"'))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

नेस्टेड if_else:

df = define(df, color=if_else(
    'Set=="Z"',
    '"red"',
    if_else('Type=="C"', '"green"', '"blue"')))

print(df)                            
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B   blue
3   Y    C  green

10

हो सकता है कि पंडों के नए अपडेट से यह संभव हो गया हो, लेकिन मुझे लगता है कि इस सवाल का अब तक का सबसे छोटा और शायद सबसे अच्छा जवाब है। आप .locविधि का उपयोग कर सकते हैं और अपनी आवश्यकता के आधार पर एक शर्त या कई का उपयोग कर सकते हैं ।

कोड सारांश:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"

#practice!
df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

स्पष्टीकरण:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))

# df so far: 
  Type Set  
0    A   Z 
1    B   Z 
2    B   X 
3    C   Y

'रंग' कॉलम जोड़ें और सभी मानों को "लाल" पर सेट करें

df['Color'] = "red"

अपनी एकल स्थिति लागू करें:

df.loc[(df['Set']=="Z"), 'Color'] = "green"


# df: 
  Type Set  Color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

या कई शर्तें यदि आप चाहते हैं:

df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

आप पंडों के तार्किक ऑपरेटरों और सशर्त चयन पर यहाँ पढ़ सकते हैं: पंडों में बूलियन अनुक्रमण के लिए तार्किक संचालक


2
अब तक का सबसे अच्छा। आप शायद अधिक शर्तों के लिए जोड़ सकते हैं जो कोड होगाdf.loc[(df['Set']=="Z") & (df['Type']=="A"), 'Color'] = "green"
सल्वाडोर विगो

2
यह स्वीकृत उत्तर होना चाहिए। वास्तव में मुहावरेदार और एक्स्टेंसिबल।
AMC

1

.apply()विधि के साथ एक लाइनर निम्नलिखित है:

df['color'] = df['Set'].apply(lambda set_: 'green' if set_=='Z' else 'red')

उसके बाद, dfडेटा फ्रेम इस तरह दिखता है:

>>> print(df)
  Type Set  color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

0

यदि आप बड़े पैमाने पर डेटा के साथ काम कर रहे हैं, तो एक ज्ञापन दृष्टिकोण सबसे अच्छा होगा:

# First create a dictionary of manually stored values
color_dict = {'Z':'red'}

# Second, build a dictionary of "other" values
color_dict_other = {x:'green' for x in df['Set'].unique() if x not in color_dict.keys()}

# Next, merge the two
color_dict.update(color_dict_other)

# Finally, map it to your column
df['color'] = df['Set'].map(color_dict)

यह दृष्टिकोण सबसे तेज़ होगा जब आपके पास कई दोहराया मान होंगे। अंगूठे का मेरा सामान्य नियम है: data_size> 10**4और n_distinct<data_size/4

पूर्व मामले में ज्ञापन 10,000 पंक्तियों में 2,500 या उससे कम भिन्न मानों के साथ।


ठीक है, इसलिए मानचित्र में केवल 2 अलग-अलग मानों के साथ, 100,000,000 पंक्तियां, "मेमोइज़ेशन" के बिना चलने में 6.67 सेकंड लगते हैं, और 9.86 सेकंड।
एएमसी

100,000,000 पंक्तियाँ, 52 अलग-अलग मूल्य, जहां उन मानचित्रों में से 1 पहले आउटपुट मान के लिए, और अन्य 51 सभी दूसरे के अनुरूप हैं: 7.99 सेकंड संस्मरण के बिना, 11.1 सेकंड।
एएमसी

क्या आपके मूल्य यादृच्छिक क्रम में हैं? या वे बैक टू बैक हैं? पांडा की उच्च गति @AMC
Yaakov Bressler

1
क्या आपके मूल्य यादृच्छिक क्रम में हैं? या वे बैक टू बैक हैं? मान यादृच्छिक होते हैं, जिनका उपयोग करके चयन किया जाता है random.choices()
एएमसी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.