पंडों में मानचित्र, लागू करने और लागू करने के तरीकों के बीच अंतर


465

क्या आप बता सकते हैं कि मूलभूत उदाहरणों के साथ इन सदिश विधियों का उपयोग कब करना है?

मैं देखता हूं कि mapयह एक Seriesविधि है जबकि बाकी DataFrameविधियां हैं। मैं हालांकि applyऔर applymapतरीकों के बारे में भ्रमित हो गया । किसी DataFrame में फ़ंक्शन को लागू करने के लिए हमारे पास दो तरीके क्यों हैं? फिर, सरल उदाहरण जो उपयोग को स्पष्ट करते हैं वह बहुत अच्छा होगा!


5
यदि मैं गलत हूं तो मुझे सुधारें, लेकिन मेरा मानना ​​है कि वे कार्य विधियां नहीं कर रहे हैं क्योंकि वे सभी उन तत्वों पर एक लूप शामिल करते हैं जिन पर वे लागू होते हैं।
टंगुवी

1
मैं यहाँ अंतर नहीं देख सकता: gist.github.com/MartinThoma/e320cbb937afb4ff766f75988f1c65e6
मार्टिन थोमा

जवाबों:


533

डेटा विश्लेषण पुस्तक, पेज के लिए वेस मैककिनी के पायथन से सीधे । 132 (मैंने इस पुस्तक की अत्यधिक अनुशंसा की है):

एक और लगातार ऑपरेशन प्रत्येक कॉलम या पंक्ति में 1D सरणियों पर एक फ़ंक्शन लागू कर रहा है। DataFrame की लागू विधि ठीक यही करती है:

In [116]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [117]: frame
Out[117]: 
               b         d         e
Utah   -0.029638  1.081563  1.280300
Ohio    0.647747  0.831136 -1.549481
Texas   0.513416 -0.884417  0.195343
Oregon -0.485454 -0.477388 -0.309548

In [118]: f = lambda x: x.max() - x.min()

In [119]: frame.apply(f)
Out[119]: 
b    1.133201
d    1.965980
e    2.829781
dtype: float64

सबसे आम सरणी आँकड़ों में से कई (जैसे योग और माध्य) DataFrame विधियाँ हैं, इसलिए आवेदन का उपयोग करना आवश्यक नहीं है।

तत्व-वार पाइथन कार्यों का उपयोग किया जा सकता है, भी। मान लीजिए कि आप फ्रेम में प्रत्येक फ्लोटिंग पॉइंट मान से एक स्वरूपित स्ट्रिंग की गणना करना चाहते थे। आप इसे अप्पम के साथ कर सकते हैं:

In [120]: format = lambda x: '%.2f' % x

In [121]: frame.applymap(format)
Out[121]: 
            b      d      e
Utah    -0.03   1.08   1.28
Ohio     0.65   0.83  -1.55
Texas    0.51  -0.88   0.20
Oregon  -0.49  -0.48  -0.31

नाम लागू करने का कारण यह है कि श्रृंखला में तत्व-वार फ़ंक्शन को लागू करने के लिए एक मानचित्र विधि है:

In [122]: frame['e'].map(format)
Out[122]: 
Utah       1.28
Ohio      -1.55
Texas      0.20
Oregon    -0.31
Name: e, dtype: object

संक्षेप, applyएक DataFrame की एक पंक्ति / स्तंभ के आधार पर काम करता है, applymapएक DataFrame पर तत्व के लिहाज से काम करता है, और mapएक श्रृंखला पर काम करता है तत्व के लिहाज से।


31
कडाई के applymap आंतरिक रूप से के माध्यम से एक छोटे से रैप-अप पर पारित समारोह पैरामीटर के साथ लागू होते हैं (मोटे तौर पर जगह बोल कार्यान्वित किया जाता है funcकरने के लिए lambda x: [func(y) for y in x], और स्तंभ-वार लागू करने)
alko

5
स्पष्टीकरण के लिए धन्यवाद। के बाद से mapऔर applymapदोनों काम तत्व के लिहाज से, मैं एक ही विधि (या तो उम्मीद होती है mapया applymap) जो दोनों एक श्रृंखला है और एक DataFrame के लिए काम करेगा। संभवतः अन्य डिजाइन विचार हैं, और वेस मैककिनी ने दो अलग-अलग तरीकों के साथ आने का फैसला किया।
नौ

2
यह किसी कारण से मेरी कॉपी में पेज 129 पर है। दूसरे संस्करण या किसी भी चीज़ के लिए कोई लेबल नहीं है।
जोडी

1
क्या पंडों में समारोह applymapके साथ-साथ एक तरीका है groupby?
everestial007

समूहबद्ध कॉलमवाइज़ डेटा पर फ़ंक्शन कैसे लागू करें?
hhh

80

तुलना map, applymapऔर : प्रसंग मामलेapply

पहला प्रमुख अंतर: परिभाषा

  • map केवल श्रृंखला पर परिभाषित किया गया है
  • applymap केवल DataFrames पर परिभाषित किया गया है
  • apply दोनों पर परिभाषित किया गया है

दूसरा प्रमुख अंतर: INPUT ARGUMENT

  • mapdictएस, Seriesया कॉल करने योग्य स्वीकार करता है
  • applymapऔर applyकेवल कॉल स्वीकार करते हैं

तीसरा प्रमुख अंतर: BEHAVIOR

  • map श्रृंखला के लिए प्राथमिक है
  • applymap DataFrames के लिए तत्व है
  • applyयह तत्व-रूप से भी काम करता है, लेकिन अधिक जटिल संचालन और एकत्रीकरण के अनुकूल है। व्यवहार और वापसी मूल्य फ़ंक्शन पर निर्भर करता है।

चौथा प्रमुख अंतर (सबसे महत्वपूर्ण): USE CASE

  • mapएक डोमेन से दूसरे में मान मैप करने के लिए है, इसलिए प्रदर्शन के लिए अनुकूलित है (जैसे, df['A'].map({1:'a', 2:'b', 3:'c'}))
  • applymapकई पंक्तियों / स्तंभों (जैसे, df[['A', 'B', 'C']].applymap(str.strip)) पर तत्व परिवर्तन के लिए अच्छा है
  • applyकिसी भी फ़ंक्शन को लागू करने के लिए है जिसे वेक्टर नहीं किया जा सकता (जैसे, df['sentences'].apply(nltk.sent_tokenize))

सारांश

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

फुटनोट

  1. mapजब कोई शब्दकोश / श्रृंखला पास की जाती है, तो उस शब्दकोश / श्रृंखला की कुंजियों के आधार पर तत्वों को मैप करेगा। गुम मानों को आउटपुट में NaN के रूप में दर्ज किया जाएगा।
  2. applymapहाल के संस्करणों में कुछ कार्यों के लिए अनुकूलित किया गया है। आप कुछ मामलों की applymapतुलना applyमें थोड़ा तेज पाएंगे । मेरा सुझाव उन दोनों का परीक्षण करना है और जो भी बेहतर काम करता है उसका उपयोग करना है।

  3. mapतत्वपूर्ण मैपिंग और परिवर्तन के लिए अनुकूलित है। संचालन जिसमें शब्दकोशों या श्रृंखला शामिल हैं, पांडा को बेहतर प्रदर्शन के लिए तेज़ कोड पथ का उपयोग करने में सक्षम करेगा।

  4. Series.applyएकत्रीकरण संचालन के लिए एक स्केलर देता है, श्रृंखला अन्यथा। इसी तरह के लिए DataFrame.apply। ध्यान दें कि applyजब इस तरह के रूप में कुछ NumPy कार्यों के साथ कहा जाता है भी fastpaths है mean, sumआदि

70

इन उत्तरों में बहुत अच्छी जानकारी है, लेकिन मैं अपने आप को स्पष्ट रूप से संक्षेप में जोड़ रहा हूं कि कौन से तरीके सरणी-वार बनाम तत्व-वार काम करते हैं। jeremiahbuddha ने ज्यादातर ऐसा किया, लेकिन Series.apply का उल्लेख नहीं किया। मैं टिप्पणी करने के लिए प्रतिनिधि नहीं है।

  • DataFrame.apply एक समय में पूरी पंक्तियों या स्तंभों पर कार्य करता है।

  • DataFrame.applymap, Series.applyऔर Series.mapसमय पर एक तत्व पर काम करते हैं।

वहाँ की क्षमताओं के बीच ओवरलैप के एक बहुत कुछ है Series.applyऔर Series.mapजिसका अर्थ है कि या तो एक ज्यादातर मामलों में काम करेंगे। उनके पास कुछ मामूली अंतर हैं, जिनमें से कुछ पर ओसा के जवाब में चर्चा की गई थी।


38

अन्य उत्तरों को जोड़कर, Seriesवहाँ भी मानचित्र हैं और लागू होते हैं

आवेदन एक श्रृंखला से एक DataFrame बना सकते हैं ; हालाँकि, मानचित्र सिर्फ एक श्रृंखला को किसी अन्य श्रृंखला के प्रत्येक कक्ष में रखेगा, जो शायद आप नहीं चाहते हैं।

In [40]: p=pd.Series([1,2,3])
In [41]: p
Out[31]:
0    1
1    2
2    3
dtype: int64

In [42]: p.apply(lambda x: pd.Series([x, x]))
Out[42]: 
   0  1
0  1  1
1  2  2
2  3  3

In [43]: p.map(lambda x: pd.Series([x, x]))
Out[43]: 
0    0    1
1    1
dtype: int64
1    0    2
1    2
dtype: int64
2    0    3
1    3
dtype: int64
dtype: object

इसके अलावा, अगर मेरे पास साइड इफेक्ट्स के साथ एक फ़ंक्शन है, जैसे "वेब सर्वर से कनेक्ट करें", तो मैं शायद applyस्पष्टता के लिए उपयोग करूंगा ।

series.apply(download_file_for_every_element) 

Map न केवल एक फ़ंक्शन का उपयोग कर सकते हैं, बल्कि एक शब्दकोश या एक अन्य श्रृंखला भी।मान लें कि आप क्रमपरिवर्तन में हेरफेर करना चाहते हैं

लेना

1 2 3 4 5
2 1 4 5 3

इस क्रमपरिवर्तन का वर्ग है

1 2 3 4 5
1 2 5 3 4

आप इसका उपयोग करके गणना कर सकते हैं map। यह सुनिश्चित नहीं है कि यदि स्व-आवेदन को प्रलेखित किया गया है, लेकिन यह काम करता है 0.15.1

In [39]: p=pd.Series([1,0,3,4,2])

In [40]: p.map(p)
Out[40]: 
0    0
1    1
2    4
3    2
4    3
dtype: int64

3
इसके अलावा, .apply () आपको काम में पास करने के लिए काम करता है।
neilxdims

19

@jeremiahbuddha ने उल्लेख किया है कि पंक्ति / स्तंभों पर काम करता है, जबकि आवेदन-पत्र तत्व-वार काम करता है। लेकिन ऐसा लगता है कि आप अभी भी तत्व-वार गणना के लिए आवेदन का उपयोग कर सकते हैं ...।

    frame.apply(np.sqrt)
    Out[102]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

    frame.applymap(np.sqrt)
    Out[103]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

29
इससे अच्छी पकड़ है। आपके उदाहरण में यह कार्य करता है क्योंकि np.sqrt एक ufunc है, अर्थात यदि आप इसे एक सरणी देते हैं, तो यह सरणी के प्रत्येक तत्व पर sqrt फ़ंक्शन को प्रसारित करेगा। इसलिए जब लागू करें प्रत्येक कॉलम पर np.sqrt पुश करता है, तो np.sqrt स्तंभों के प्रत्येक तत्व पर स्वयं काम करता है, इसलिए आपको अनिवार्य रूप से एक ही परिणाम प्राप्त हो रहा है जैसे कि आवेदनपत्र।
जेरमैयाबुद्ध १६'१४

11

बस इशारा करना चाहता था, क्योंकि मैंने इसके लिए थोड़ा संघर्ष किया

def f(x):
    if x < 0:
        x = 0
    elif x > 100000:
        x = 100000
    return x

df.applymap(f)
df.describe()

यह डेटाफ्रेम को ही संशोधित नहीं करता है, इसे फिर से असाइन करना होगा

df = df.applymap(f)
df.describe()

1
मुझे कभी-कभी यह पता लगाने में परेशानी होती है कि आपको डीएफ के साथ कुछ करने के बाद फिर से असाइन करना है या नहीं। यह मेरे लिए ज्यादातर परीक्षण और त्रुटि है, लेकिन मुझे यकीन है कि यह कैसे काम करता है एक तर्क है (कि मैं याद कर रहा हूं)।
Marillion

2
सामान्य तौर पर, एक पांडा डेटाफ्रेम को केवल df = modified_dfया तो पुन: असाइन करके संशोधित किया जाता है या यदि आप inplace=Trueध्वज सेट करते हैं । यदि आप किसी फ़ंक्शन के लिए कोई डेटाफ़्रेम पास करते हैं तो डेटाफ़्रेम बदल जाएगा और फ़ंक्शन डेटाफ़्रेम को संशोधित करता है
muon

1
यह पूरी तरह से सच नहीं है, इसके बारे में सोचें .ixया .whereसुनिश्चित न करें कि पूर्ण विवरण क्या है जब आपको फिर से असाइन करने की आवश्यकता होती है और कब नहीं।
थानोस

10

संभवतः सरलतम स्पष्टीकरण लागू करने और लागू करने के बीच का अंतर:

लागू पूरे कॉलम को एक पैरामीटर के रूप में लेता है और फिर इस कॉलम को परिणाम असाइन करता है

applymap एक अलग सेल वैल्यू को एक पैरामीटर के रूप में लेता है और परिणाम को इस सेल में वापस असाइन करता है।

NB यदि लागू होने वाला एकल मान लौटाता है तो असाइन करने के बाद कॉलम के बजाय आपके पास यह मान होगा और अंततः मैट्रिक्स के बजाय सिर्फ एक पंक्ति होगी।


3

मेरी समझ:

फ़ंक्शन के दृष्टिकोण से:

यदि फ़ंक्शन में वैरिएबल हैं जो किसी स्तंभ / पंक्ति के भीतर तुलना करने की आवश्यकता है, तो उपयोग करें apply

उदाहरण के लिए: lambda x: x.max()-x.mean()

यदि फ़ंक्शन को प्रत्येक तत्व पर लागू किया जाना है:

1> यदि कोई स्तंभ / पंक्ति स्थित है, तो उपयोग करें apply

2> यदि संपूर्ण डेटाफ़्रेम पर लागू होता है, तो उपयोग करें applymap

majority = lambda x : x > 17
df2['legal_drinker'] = df2['age'].apply(majority)

def times10(x):
  if type(x) is int:
    x *= 10 
  return x
df2.applymap(times10)

कृपया बेहतर स्पष्टता के लिए df2 भी प्रदान करें ताकि हम आपके कोड का परीक्षण कर सकें।
आशीष आनंद

1

Cs95 के उत्तर के आधार पर

  • map केवल श्रृंखला पर परिभाषित किया गया है
  • applymap केवल DataFrames पर परिभाषित किया गया है
  • apply दोनों पर परिभाषित किया गया है

कुछ उदाहरण दीजिए

In [3]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [4]: frame
Out[4]:
            b         d         e
Utah    0.129885 -0.475957 -0.207679
Ohio   -2.978331 -1.015918  0.784675
Texas  -0.256689 -0.226366  2.262588
Oregon  2.605526  1.139105 -0.927518

In [5]: myformat=lambda x: f'{x:.2f}'

In [6]: frame.d.map(myformat)
Out[6]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [7]: frame.d.apply(myformat)
Out[7]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [8]: frame.applymap(myformat)
Out[8]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93

In [9]: frame.apply(lambda x: x.apply(myformat))
Out[9]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93


In [10]: myfunc=lambda x: x**2

In [11]: frame.applymap(myfunc)
Out[11]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

In [12]: frame.apply(myfunc)
Out[12]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

0

FOMO:

निम्न उदाहरण दिखाता है applyऔर applymapएक पर लागू होता है DataFrame

mapफ़ंक्शन कुछ है जो आप केवल श्रृंखला पर लागू करते हैं। आप map DataFrame पर आवेदन नहीं कर सकते ।

याद करने के लिए बात यह है कि applyक्या कर सकते हैं कुछ भी applymap कर सकते हैं, लेकिन applyहै अतिरिक्त विकल्प।

X कारक विकल्प हैं: axisऔर result_typeजहां result_typeकेवल axis=1(कॉलम के लिए) काम करता है ।

df = DataFrame(1, columns=list('abc'),
                  index=list('1234'))
print(df)

f = lambda x: np.log(x)
print(df.applymap(f)) # apply to the whole dataframe
print(np.log(df)) # applied to the whole dataframe
print(df.applymap(np.sum)) # reducing can be applied for rows only

# apply can take different options (vs. applymap cannot)
print(df.apply(f)) # same as applymap
print(df.apply(sum, axis=1))  # reducing example
print(df.apply(np.log, axis=1)) # cannot reduce
print(df.apply(lambda x: [1, 2, 3], axis=1, result_type='expand')) # expand result

एक सिडेनोट के रूप में, श्रृंखला mapफ़ंक्शन, पायथन mapफ़ंक्शन के साथ भ्रमित नहीं होना चाहिए ।

पहला एक श्रृंखला पर लागू किया जाता है, मूल्यों को मैप करने के लिए, और दूसरा एक पुनरावृत्त के प्रत्येक आइटम के लिए।


अंतिम रूप से डेटाफ्रेम applyविधि को ग्रुपबी applyविधि से भ्रमित न करें ।

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