एक ताना-बाना के साथ पंडों के कॉलम में रीमैप मूल्य


317

मेरे पास एक शब्दकोश है जो इस तरह दिखता है: di = {1: "A", 2: "B"}

मैं इसे डेटाफ़्रेम के "col1" कॉलम के समान लागू करना चाहूंगा:

     col1   col2
0       w      a
1       1      2
2       2    NaN

लेना:

     col1   col2
0       w      a
1       A      2
2       B    NaN

मैं यह कैसे कर सकता हूं? किसी कारण से इस से संबंधित googling शर्तें मुझे केवल लिंक दिखाती है कि कैसे dicts और इसके विपरीत से कॉलम बनाने के लिए: - /

जवाबों:


340

आप उपयोग कर सकते हैं .replace। उदाहरण के लिए:

>>> df = pd.DataFrame({'col2': {0: 'a', 1: 2, 2: np.nan}, 'col1': {0: 'w', 1: 1, 2: 2}})
>>> di = {1: "A", 2: "B"}
>>> df
  col1 col2
0    w    a
1    1    2
2    2  NaN
>>> df.replace({"col1": di})
  col1 col2
0    w    a
1    A    2
2    B  NaN

या सीधे Seriesयानी पर df["col1"].replace(di, inplace=True)


1
यह मेरे लिए तब काम नहीं करता जब मैं col```` is tuple. The error info is टाइप नहीं कर सकता 'ndarray (dtype = object)' और 'tuple'```
Pengju Zhao

18
ऐसा लगता है कि यह अब और काम नहीं करता है सब पर है, जो दिया आश्चर्य की बात नहीं है इस सवाल का जवाब 4 साल पहले से था। इस सवाल के नए जवाब की जरूरत है कि ऑपरेशन कितना सामान्य है ...
प्रेस्टोन एचएच

2
@PrestonH यह मेरे लिए पूरी तरह से काम करता है। चल रहा है:'3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]'
दान

इससे मेरा काम बनता है। लेकिन अगर मैं सभी कॉलमों में मानों को बदलना चाहता हूं तो कैसे करें?
अकालगर

2
मेरे द्वारा दिखाए गए उत्तरों के लिए काम करने का एकमात्र तरीका श्रृंखला पर प्रत्यक्ष प्रतिस्थापन करना था। धन्यवाद!
डिरिगो

242

map की तुलना में बहुत तेज हो सकता है replace

यदि आपके शब्दकोश में दो से अधिक कुंजियाँ हैं, तो उपयोग mapकरना इससे अधिक तेज़ हो सकता है replace। इस दृष्टिकोण के दो संस्करण हैं, यह इस बात पर निर्भर करता है कि क्या आपका शब्दकोश सभी संभावित मूल्यों को मैप करता है (और यह भी कि क्या आप गैर-मिलान चाहते हैं कि उनके मान रखें या NaN में परिवर्तित हो जाएं):

अत्यधिक मानचित्रण

इस मामले में, फ़ॉर्म बहुत सरल है:

df['col1'].map(di)       # note: if the dictionary does not exhaustively map all
                         # entries then non-matched entries are changed to NaNs

हालाँकि, mapआमतौर पर एक फ़ंक्शन को इसके तर्क के रूप में लिया जाता है, यह वैकल्पिक रूप से एक शब्दकोश या श्रृंखला ले सकता है: पांडास के लिए दस्तावेज़ीकरण।

गैर-थकाऊ मानचित्रण

यदि आपके पास गैर-निकास मानचित्रण है और आप गैर-मैचों के लिए मौजूदा चर को बनाए रखना चाहते हैं, तो आप जोड़ सकते हैं fillna:

df['col1'].map(di).fillna(df['col1'])

जैसा कि @ jpp का उत्तर यहाँ है: शब्दकोश के माध्यम से एक पांडा श्रृंखला में मूल्यों को कुशलता से बदलें

मानक

पांडा संस्करण 0.23.1 के साथ निम्नलिखित डेटा का उपयोग करना:

di = {1: "A", 2: "B", 3: "C", 4: "D", 5: "E", 6: "F", 7: "G", 8: "H" }
df = pd.DataFrame({ 'col1': np.random.choice( range(1,9), 100000 ) })

और %timeitइसके साथ परीक्षण , यह प्रतीत होता है कि mapकी तुलना में लगभग 10x तेज है replace

ध्यान दें कि आपका स्पीडअप mapआपके डेटा के साथ अलग-अलग होगा। सबसे बड़ा स्पीडअप बड़े शब्दकोश और संपूर्ण प्रतिकृति के साथ प्रतीत होता है। अधिक व्यापक बेंचमार्क और चर्चा के लिए @jpp उत्तर (उपरोक्त लिंक) देखें।


17
इस उत्तर के लिए कोड का अंतिम ब्लॉक निश्चित रूप से सबसे सुरुचिपूर्ण नहीं है, लेकिन यह उत्तर कुछ क्रेडिट का हकदार है। यह बड़े शब्दकोशों के लिए तेजी से परिमाण का आदेश है और मेरे सभी रैम का उपयोग नहीं करता है। इसने एक शब्दकोश का उपयोग करते हुए 10,000 लाइन की फाइल को रीमेक किया जिसमें आधे मिनट में लगभग 9 मिलियन प्रविष्टियां थीं। df.replaceसमारोह है, जबकि साफ और छोटे dicts के लिए उपयोगी, 20 मिनट या तो के लिए चलाने के बाद दुर्घटनाग्रस्त हो गया।
ग्रिफिन


@griffinc प्रतिक्रिया के लिए धन्यवाद और ध्यान दें कि मैंने तब से इस उत्तर को बहुत ही सरल तरीके से अद्यतन किया है ताकि गैर-थकाऊ मामला (@jpp के लिए धन्यवाद)
JohnE

1
mapयह भी एक सूचकांक पर काम करता है जहां मैं ऐसा करने का एक तरीका नहीं निकाल सकाreplace
मैक्स गनीस

1
@AlexSB मैं पूरी तरह से सामान्य उत्तर नहीं दे सकता, लेकिन मुझे लगता है कि नक्शा बहुत तेज होगा और एक ही बात को पूरा करेगा (मुझे लगता है)। आम तौर पर, मर्ज अन्य विकल्पों की तुलना में धीमा होने जा रहा है जो समान कार्य करते हैं।
23

59

आपके प्रश्न में थोड़ी अस्पष्टता है। कम से कम तीन दो व्याख्याएँ हैं:

  1. diसूचकांक मूल्यों के संदर्भ में कुंजी
  2. मूल्यों के diसंदर्भ में चाबियाँdf['col1']
  3. diसूचकांक स्थानों के संदर्भ में कुंजियाँ (ओपी का सवाल नहीं है, लेकिन मज़े के लिए फेंक दिया गया है।)

नीचे प्रत्येक मामले के लिए एक समाधान है।


केस 1: यदि diइंडेक्स वैल्यू को संदर्भित करने के लिए कुंजियों का उपयोग किया जाता है, तो आप updateविधि का उपयोग कर सकते हैं :

df['col1'].update(pd.Series(di))

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

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
#   col1 col2
# 1    w    a
# 2   10   30
# 0   20  NaN

di = {0: "A", 2: "B"}

# The value at the 0-index is mapped to 'A', the value at the 2-index is mapped to 'B'
df['col1'].update(pd.Series(di))
print(df)

पैदावार

  col1 col2
1    w    a
2    B   30
0    A  NaN

मैंने आपके मूल पोस्ट से मानों को संशोधित किया है इसलिए यह स्पष्ट है कि क्या updateकर रहा है। ध्यान दें कि diइंडेक्स मानों के साथ कुंजियाँ किस प्रकार जुड़ी हुई हैं। सूचकांक मानों का क्रम - यानी सूचकांक स्थान - कोई फर्क नहीं पड़ता।


केस 2: यदि मानों के diसंदर्भ में कुंजियाँ df['col1']हैं, तो @DanAllan और @DSM यह दर्शाते हैं कि इसे कैसे प्राप्त किया जाए replace:

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
print(df)
#   col1 col2
# 1    w    a
# 2   10   30
# 0   20  NaN

di = {10: "A", 20: "B"}

# The values 10 and 20 are replaced by 'A' and 'B'
df['col1'].replace(di, inplace=True)
print(df)

पैदावार

  col1 col2
1    w    a
2    A   30
0    B  NaN

ध्यान दें कि इस मामले में कुंजी diको मूल्यों में मिलान करने के लिए कैसे बदला गया था df['col1']


केस 3: यदि diइंडेक्स स्थानों के संदर्भ में कुंजी है , तो आप उपयोग कर सकते हैं

df['col1'].put(di.keys(), di.values())

जबसे

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
di = {0: "A", 2: "B"}

# The values at the 0 and 2 index locations are replaced by 'A' and 'B'
df['col1'].put(di.keys(), di.values())
print(df)

पैदावार

  col1 col2
1    A    a
2   10   30
0    B  NaN

यहां, पहली और तीसरी पंक्तियों को बदल दिया गया था, क्योंकि चाबियाँ diहैं 0और 2, जो पायथन के 0-आधारित अनुक्रमण के साथ पहले और तीसरे स्थानों को संदर्भित करती हैं।


replaceसमान रूप से अच्छा है, और शायद यहाँ क्या हो रहा है के लिए एक बेहतर शब्द।
दान एलन

क्या ओपी द्वारा पोस्ट किया गया लक्ष्य डेटाफ़्रेम अस्पष्टता को समाप्त नहीं करता है? फिर भी, यह उत्तर उपयोगी है, इसलिए +1।
डीएसएम

@DSM: ओह, आप सही कह रहे हैं कि Case3 की कोई संभावना नहीं है, लेकिन मुझे नहीं लगता कि OP का लक्ष्य डेटाफ्रेम Case1 से Case1 को अलग करता है क्योंकि सूचकांक मान स्तंभ मानों के बराबर है।
२०

दूसरों की एक संख्या की तरह, @ डीएसएम की विधि दुर्भाग्य से मेरे लिए काम नहीं करती थी, लेकिन @ अनटुब के मामले 1 ने काम किया। update()की तुलना में थोड़ा कम लगता है replace(), लेकिन कम से कम यह काम करता है।
ज्योफ

4

इस सवाल को जोड़ना अगर आपके पास डेटा डेटाफ़्रेम में रीमैप करने के लिए एक से अधिक कॉलम हैं:

def remap(data,dict_labels):
    """
    This function take in a dictionnary of labels : dict_labels 
    and replace the values (previously labelencode) into the string.

    ex: dict_labels = {{'col1':{1:'A',2:'B'}}

    """
    for field,values in dict_labels.items():
        print("I am remapping %s"%field)
        data.replace({field:values},inplace=True)
    print("DONE")

    return data

आशा है कि यह किसी के लिए उपयोगी हो सकता है।

चियर्स


1
यह कार्यक्षमता पहले से ही प्रदान की गई है DataFrame.replace(), हालांकि मुझे नहीं पता कि इसे कब जोड़ा गया था।
एएमसी

3

DSM के पास स्वीकृत उत्तर है, लेकिन कोडिंग सभी के लिए काम नहीं करती है। यहाँ वह है जो पांडा के वर्तमान संस्करण के साथ काम करता है (०.२३.४ के रूप में ).२०१ with):

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 2, 3, 1],
            'col2': ['negative', 'positive', 'neutral', 'neutral', 'positive']})

conversion_dict = {'negative': -1, 'neutral': 0, 'positive': 1}
df['converted_column'] = df['col2'].replace(conversion_dict)

print(df.head())

आप देखेंगे कि ऐसा दिखता है:

   col1      col2  converted_column
0     1  negative                -1
1     2  positive                 1
2     2   neutral                 0
3     3   neutral                 0
4     1  positive                 1

पंडों के लिए दस्तावेज़ । DataFrame.replace यहाँ हैं


मुझे चलाने में DSM का जवाब पाने में कभी कोई समस्या नहीं हुई और मुझे लगता है कि उच्च वोट कुल अन्य लोगों को दिया था या तो नहीं दिया। आप चाहते हैं कि आप जो समस्या हो रही है, उसके बारे में अधिक विशिष्ट हो। हो सकता है कि यह आपके नमूना डेटा के साथ करना है जो डीएसएम से अलग है?
जॉनी

हम्म, शायद एक संस्करण मुद्दा। फिर भी, दोनों उत्तर अब यहाँ हैं।
वर्डफेयर वाइज

1
स्वीकृत उत्तर में समाधान केवल कुछ प्रकारों पर काम करता है, Series.map()अधिक लचीला लगता है।
एएमसी

2

या करें apply:

df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))

डेमो:

>>> df['col1']=df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
>>> df
  col1 col2
0    w    a
1    1    2
2    2  NaN
>>> 

क्या होता है जब आपका diतानाशाह सूचियों का एक तानाशाह होता है? आप सूची में केवल एक मान कैसे मैप कर सकते हैं?
फ़ॉफ़ी

आप कर सकते हैं, हालांकि मैं यह नहीं देखता कि आप क्यों करेंगे।
एएमसी

2

दिए गए mapप्रतिस्थापन (@ जॉन्स सॉल्यूशन) की तुलना में तेज़ है, आपको गैर-NaN अत्यधिक मैप्पिंग से सावधान रहने की आवश्यकता है जहाँ आप विशिष्ट मूल्यों को मैप करने का इरादा रखते हैं । इस मामले में उचित विधि के लिए आवश्यक है कि आप maskश्रृंखला, जब आप .fillnaमानचित्रण को पूर्ववत करें NaN

import pandas as pd
import numpy as np

d = {'m': 'Male', 'f': 'Female', 'missing': np.NaN}
df = pd.DataFrame({'gender': ['m', 'f', 'missing', 'Male', 'U']})

keep_nan = [k for k,v in d.items() if pd.isnull(v)]
s = df['gender']

df['mapped'] = s.map(d).fillna(s.mask(s.isin(keep_nan)))

    gender  mapped
0        m    Male
1        f  Female
2  missing     NaN
3     Male    Male
4        U       U

1

एक अच्छा पूर्ण समाधान जो आपके वर्ग लेबल का एक नक्शा रखता है:

labels = features['col1'].unique()
labels_dict = dict(zip(labels, range(len(labels))))
features = features.replace({"col1": labels_dict})

इस तरह, आप किसी भी बिंदु पर मूल वर्ग लेबल से लेबल_डिक्ट का उल्लेख कर सकते हैं।


1

Nico Coallier (कई कॉलमों पर लागू) और U10- फ़ॉरवर्ड (विधियों की लागू शैली का उपयोग करके) द्वारा प्रस्तावित किए गए एक विस्तार के रूप में, और इसे एक-लाइनर में प्रस्तुत करने का प्रस्ताव देता हूं:

df.loc[:,['col1','col2']].transform(lambda x: x.map(lambda x: {1: "A", 2: "B"}.get(x,x))

.transform()एक श्रृंखला के रूप में प्रत्येक स्तंभ संसाधित करता है। .apply()जिसके विपरीत एक DataFrame में एकत्र किए गए कॉलम को पास करता है।

नतीजतन आप श्रृंखला पद्धति को लागू कर सकते हैं map()

अंत में, और मैंने U10 की बदौलत इस व्यवहार की खोज की, आप संपूर्ण श्रृंखला को .get () अभिव्यक्ति में उपयोग कर सकते हैं। जब तक मैंने इसके व्यवहार को गलत नहीं समझा और यह क्रमिक रूप से कड़वाहट के बजाय श्रृंखला को संसाधित करता है। मूल्यों के लिए खातों आप अपने मानचित्रण शब्दकोश जिसके द्वारा अन्यथा नेन के रूप में विचार किया जाएगा में उल्लेख नहीं था, विधि
.get(x,x).map()


.transform()एक श्रृंखला के रूप में प्रत्येक स्तंभ संसाधित करता है। .apply()जिसके विपरीत एक DataFrame में एकत्र किए गए कॉलम को पास करता है। मैंने बस कोशिश की, apply()ठीक काम करता है। locया तो उपयोग करने की कोई आवश्यकता नहीं है , यह अत्यधिक जटिल लगता है। df[["col1", "col2"]].apply(lambda col: col.map(lambda elem: my_dict.get(elem, elem)))बस ठीक काम करना चाहिए। खातों मूल्यों के लिए आप अपने मानचित्रण शब्दकोश जिसके द्वारा अन्यथा नेन के रूप में विचार किया जाएगा में उल्लेख नहीं था, विधि तुम भी इस्तेमाल कर सकते हैं बाद में। .get(x,x).map()fillna()
AMC

अंत में, और मैंने U10 की बदौलत इस व्यवहार की खोज की, आप संपूर्ण श्रृंखला को .get () अभिव्यक्ति में उपयोग कर सकते हैं। जब तक मैंने इसके व्यवहार को गलत नहीं समझा और यह क्रमिक रूप से कड़वाहट के बजाय श्रृंखला को संसाधित करता है। मैं इसे पुन: पेश नहीं कर सकता, क्या आप विस्तृत कर सकते हैं? संभवतः नामांकित चर यहां कुछ भूमिका निभा रहे हैं।
एएमसी

0

एक अधिक देशी पांडा दृष्टिकोण नीचे के रूप में एक प्रतिस्थापित कार्य लागू करने के लिए है:

def multiple_replace(dict, text):
  # Create a regular expression  from the dictionary keys
  regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))

  # For each match, look-up corresponding value in dictionary
  return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) 

एक बार जब आप फ़ंक्शन को परिभाषित करते हैं, तो आप इसे अपने डेटाफ़्रेम पर लागू कर सकते हैं।

di = {1: "A", 2: "B"}
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1)

पंडों द्वारा प्रदान किए गए बहुत सरल तरीकों की तुलना में अधिक देशी पंडों का दृष्टिकोण नीचे दिए गए फ़ंक्शन को लागू करने के लिए कैसे है कि अधिक "देशी" (मुहावरेदार) है?
एएमसी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.