अलग कॉलम में एक पंडों कॉलम के अंदर शब्दकोश / सूची का विभाजन


147

मेरे पास पोस्टग्रेक्यूएल डेटाबेस में डेटा सेव है। मैं Python2.7 का उपयोग करके इस डेटा को क्वेरी कर रहा हूं और इसे पंडों के डेटाफ़्रेम में बदल रहा हूं। हालाँकि, इस डेटाफ्रेम के अंतिम कॉलम में इसके भीतर मानों का एक शब्दकोष (या सूची) है। DataFrame इस तरह दिखता है:

[1] df
Station ID     Pollutants
8809           {"a": "46", "b": "3", "c": "12"}
8810           {"a": "36", "b": "5", "c": "8"}
8811           {"b": "2", "c": "7"}
8812           {"c": "11"}
8813           {"a": "82", "c": "15"}

मुझे इस कॉलम को अलग कॉलम में विभाजित करने की आवश्यकता है ताकि DataFrame इस तरह दिखे:

[2] df2
Station ID     a      b       c
8809           46     3       12
8810           36     5       8
8811           NaN    2       7
8812           NaN    NaN     11
8813           82     NaN     15

मुख्य मुद्दा यह है कि सूचियाँ समान लंबाई नहीं हैं। लेकिन सभी सूचियां केवल 3 मानों तक ही होती हैं: ए, बी, और सी। और वे हमेशा एक ही क्रम में दिखाई देते हैं (एक पहले, दूसरे, सी तीसरे)।

निम्नलिखित कोड काम करने के लिए उपयोग किया गया था और मुझे जो चाहिए था उसे वापस करने के लिए (df2)।

[3] df 
[4] objs = [df, pandas.DataFrame(df['Pollutant Levels'].tolist()).iloc[:, :3]]
[5] df2 = pandas.concat(objs, axis=1).drop('Pollutant Levels', axis=1)
[6] print(df2)

मैं पिछले हफ्ते ही इस कोड को चला रहा था और यह ठीक काम कर रहा था। लेकिन अब मेरा कोड टूट गया है और मुझे यह त्रुटि पंक्ति [4] से मिली है:

IndexError: out-of-bounds on slice (end) 

मैंने कोड में कोई बदलाव नहीं किया है, लेकिन अब मुझे त्रुटि मिल रही है। मुझे लगता है कि यह मेरे तरीके के मजबूत या उचित नहीं होने के कारण है।

सूचियों के इस स्तंभ को अलग-अलग स्तंभों में विभाजित करने के बारे में कोई सुझाव या मार्गदर्शन सुपर सराहना की जाएगी!

संपादित करें: मुझे लगता है कि .tolist () और .apply विधियाँ मेरे कोड पर काम नहीं कर रही हैं क्योंकि यह एक यूनिकोड स्ट्रिंग है, अर्थात:

#My data format 
u{'a': '1', 'b': '2', 'c': '3'}

#and not
{u'a': '1', u'b': '2', u'c': '3'}

डेटा इस प्रारूप में पोस्टग्रेक्यूएल डेटाबेस से आयात कर रहा है। इस मुद्दे के साथ कोई मदद या विचार? क्या यूनिकोड को रूपांतरित करने का कोई तरीका है?


मैंने थोड़ा अलग समाधान के साथ उत्तर दिया, लेकिन, आपके कोड को वास्तव में बस ठीक काम करना चाहिए। नीचे मेरे डमी उदाहरण का उपयोग करते हुए, यह पांडा 0.18.1 का उपयोग करके काम करता है यदि मैं ilocभाग को छोड़ देता हूं
जॉरिस

यह का हिस्सा है कि iloc[:, :3]मान लिया गया है वहाँ 3 आइटम हो जाएगा, और हो सकता है और हाल ही में डेटा स्लाइस केवल 1 या 2 (जैसे कोई हो को भी हो है bमें की तरह index 8813)?
19

जवाबों:


167

स्ट्रिंग को वास्तविक रूप से परिवर्तित करने के लिए, आप कर सकते हैं df['Pollutant Levels'].map(eval)। बाद में, नीचे दिए गए समाधान का उपयोग तानाशाही को विभिन्न स्तंभों में बदलने के लिए किया जा सकता है।


एक छोटे से उदाहरण का उपयोग कर, आप उपयोग कर सकते हैं .apply(pd.Series):

In [2]: df = pd.DataFrame({'a':[1,2,3], 'b':[{'c':1}, {'d':3}, {'c':5, 'd':6}]})

In [3]: df
Out[3]:
   a                   b
0  1           {u'c': 1}
1  2           {u'd': 3}
2  3  {u'c': 5, u'd': 6}

In [4]: df['b'].apply(pd.Series)
Out[4]:
     c    d
0  1.0  NaN
1  NaN  3.0
2  5.0  6.0

बाकी डेटाफ़्रेम के साथ इसे संयोजित करने के लिए, आप concatउपरोक्त परिणाम के साथ अन्य कॉलम कर सकते हैं :

In [7]: pd.concat([df.drop(['b'], axis=1), df['b'].apply(pd.Series)], axis=1)
Out[7]:
   a    c    d
0  1  1.0  NaN
1  2  NaN  3.0
2  3  5.0  6.0

अपने कोड का उपयोग करना, यह भी काम करता है अगर मैं ilocभाग छोड़ देता हूं :

In [15]: pd.concat([df.drop('b', axis=1), pd.DataFrame(df['b'].tolist())], axis=1)
Out[15]:
   a    c    d
0  1  1.0  NaN
1  2  NaN  3.0
2  3  5.0  6.0

2
मैं pd.DataFrame(df[col].tolist())लंबे समय से उपयोग कर रहा हूं , इसके बारे में कभी नहीं सोचा apply(pd.Series)। बहुत अच्छा।
अयान

1
मुझे अब समस्या का एहसास हुआ। .Apply (pd.Series) मेरे डेटासेट पर काम नहीं कर रहा है क्योंकि पूरी पंक्ति एक यूनिकोड स्ट्रिंग है। यह है: u '{' a ':' 1 ',' b ':' 2 ',' c ':' 3 '} और न कि {u'a': '1', u'b ':' 2 ', u'c ':' 3 '} जैसा कि आपके समाधान दिखाता है। इसलिए कोड इसे 3 पहचानने योग्य स्तंभों में विभाजित नहीं कर सकता है।
लालाफिन

2
@ayhan वास्तव में, यह परीक्षण किया है, और DataFrame(df['col'].tolist())दृष्टिकोण लागू दृष्टिकोण की तुलना में काफी तेज है!
जॉरिस

3
@llaffin यदि यह एक स्ट्रिंग है, तो आप df[col].map(eval)इसे डेटाफ़्रेम में बदलने से पहले एक वास्तविक डिक्टेट में परिवर्तित कर सकते हैं
जॉरिस

2
सही काम करता है, लेकिन नए समाधान (2019) की तुलना में धीमा है (लेच बिर्क स्टैकओवरफ्लो.com
a

85

मुझे पता है कि प्रश्न काफी पुराना है, लेकिन मैं यहां उत्तर खोज रहा हूं। वास्तव में इसका उपयोग करने का अब एक बेहतर (और तेज़) तरीका है json_normalize:

import pandas as pd

df2 = pd.json_normalize(df['Pollutant Levels'])

यह महंगा पड़ता कार्यों को लागू करने से बचा जाता है ...


4
वाह! मैं JSON ऑब्जेक्ट्स पर पंडों में पूरे दिन थकाऊ और भ्रामक काम कर रहा हूं, और फिर मैंने इस जवाब पर ठोकर खाई और सोचा "कोई रास्ता नहीं, यह इतना आसान नहीं हो सकता था!" फिर मैंने कोशिश की और यह था। बहुत बहुत धन्यवाद!
Emac

यहाँ एकमात्र समस्या यह है कि यह बिना जोंस के अन्य कॉलमों की नकल नहीं करता है, जिसका अर्थ है कि यदि आप किसी एक पंक्ति के मानों को सामान्य करने की कोशिश कर रहे हैं, तो आपको इसे कॉपी करना होगा और दोनों को मिलाना होगा, फिर भी मेरे पुनरावृत्तियों से बहुत बेहतर होगा। तरीका। Cudos!
मिस्टर ड्रू

इस समाधान के लिए यह कैसे संभव हो सकता है कि गतिशील रूप से उन कॉलमों की सूची का चयन करें जिन्हें सामान्य बनाने की आवश्यकता है? .jsonफाइलों में जो लेन-देन का डेटा मैं ला रहा हूं वह अलग-अलग स्रोतों से आ रहा है और इसके पास हमेशा एक ही कॉलम नहीं है जो नेस्टेड हैं। मैं उन स्तंभों की एक सूची बनाने का एक तरीका खोजने की कोशिश कर रहा हूं जिनमें डक्ट होते हैं लेकिन इसे काम करने के लिए प्रतीत नहीं हो सकता है
Callum Smyth

5
from pandas.io.json import json_normalize
रामिन मेलिकोव

क्या अंतिम स्तंभों के लिए उपसर्ग लगाने का कोई तरीका है? मैंने देखा है कि जैसे तर्क meta_prefixऔर हैं record_prefix। हालाँकि, मैं अपने डेटाफ़्रेम के साथ वह काम नहीं कर सकता (अंतिम डेटाफ़्रेम मेरे मामले में सही है लेकिन मैं उपसर्गों को लागू करना चाहूंगा)।
जे। स्नो

21

इसे आज़माएं: SQL से लौटाए गए डेटा को Dict में बदलना है। या यह "Pollutant Levels" अब हो सकता हैPollutants'

   StationID                   Pollutants
0       8809  {"a":"46","b":"3","c":"12"}
1       8810   {"a":"36","b":"5","c":"8"}
2       8811            {"b":"2","c":"7"}
3       8812                   {"c":"11"}
4       8813          {"a":"82","c":"15"}


df2["Pollutants"] = df2["Pollutants"].apply(lambda x : dict(eval(x)) )
df3 = df2["Pollutants"].apply(pd.Series )

    a    b   c
0   46    3  12
1   36    5   8
2  NaN    2   7
3  NaN  NaN  11
4   82  NaN  15


result = pd.concat([df, df3], axis=1).drop('Pollutants', axis=1)
result

   StationID    a    b   c
0       8809   46    3  12
1       8810   36    5   8
2       8811  NaN    2   7
3       8812  NaN  NaN  11
4       8813   82  NaN  15

13

मर्लिन का जवाब बेहतर और सुपर आसान है, लेकिन हमें लैंबडा फ़ंक्शन की आवश्यकता नहीं है। निम्नलिखित के दो तरीकों से शब्दकोश के मूल्यांकन को सुरक्षित रूप से अनदेखा किया जा सकता है:

रास्ता 1: दो चरण

# step 1: convert the `Pollutants` column to Pandas dataframe series
df_pol_ps = data_df['Pollutants'].apply(pd.Series)

df_pol_ps:
    a   b   c
0   46  3   12
1   36  5   8
2   NaN 2   7
3   NaN NaN 11
4   82  NaN 15

# step 2: concat columns `a, b, c` and drop/remove the `Pollutants` 
df_final = pd.concat([df, df_pol_ps], axis = 1).drop('Pollutants', axis = 1)

df_final:
    StationID   a   b   c
0   8809    46  3   12
1   8810    36  5   8
2   8811    NaN 2   7
3   8812    NaN NaN 11
4   8813    82  NaN 15

तरीका 2: उपरोक्त दो चरणों को एक बार में जोड़ा जा सकता है:

df_final = pd.concat([df, df['Pollutants'].apply(pd.Series)], axis = 1).drop('Pollutants', axis = 1)

df_final:
    StationID   a   b   c
0   8809    46  3   12
1   8810    36  5   8
2   8811    NaN 2   7
3   8812    NaN NaN 11
4   8813    82  NaN 15

13

मैं 'प्रदूषक' कॉलम निकालने की विधि की दृढ़ता से अनुशंसा करता हूं:

df_pollutants = pd.DataFrame(df['Pollutants'].values.tolist(), index=df.index)

इससे बहुत तेज है

df_pollutants = df['Pollutants'].apply(pd.Series)

जब df का आकार विशाल होता है।


बहुत अच्छा होगा यदि आप बता सकते हैं कि यह कैसे / क्यों काम करता है और कितना बेहतर है! मेरे लिए यह हमेशा तेज़ होता है, और ~ 1000 पंक्तियों से अधिक प्राप्त करने पर ~ 200 गुना तेज़
सैम मेसन

@SamMason जब आप applyसंपूर्ण डेटा फ़्रेम का प्रबंधन पंडों द्वारा किया जाता है, लेकिन जब यह आता है valuesतो केवल उसी के साथ खेलता है numpy ndarraysजो शुद्ध cकार्यान्वयन होने के कारण आंतरिक रूप से तेज़ होता है ।
सागर कर

8

आप + के joinसाथ उपयोग कर सकते हैं । प्रदर्शन + के साथ तुलनीय है , लेकिन कुछ को यह वाक्यविन्यास क्लीनर मिल सकता है:poptolistconcatdroptolist

res = df.join(pd.DataFrame(df.pop('b').tolist()))

अन्य तरीकों के साथ बेंचमार्किंग:

df = pd.DataFrame({'a':[1,2,3], 'b':[{'c':1}, {'d':3}, {'c':5, 'd':6}]})

def joris1(df):
    return pd.concat([df.drop('b', axis=1), df['b'].apply(pd.Series)], axis=1)

def joris2(df):
    return pd.concat([df.drop('b', axis=1), pd.DataFrame(df['b'].tolist())], axis=1)

def jpp(df):
    return df.join(pd.DataFrame(df.pop('b').tolist()))

df = pd.concat([df]*1000, ignore_index=True)

%timeit joris1(df.copy())  # 1.33 s per loop
%timeit joris2(df.copy())  # 7.42 ms per loop
%timeit jpp(df.copy())     # 7.68 ms per loop

3

एक पंक्ति समाधान निम्नलिखित है:

>>> df = pd.concat([df['Station ID'], df['Pollutants'].apply(pd.Series)], axis=1)
>>> print(df)
   Station ID    a    b   c
0        8809   46    3  12
1        8810   36    5   8
2        8811  NaN    2   7
3        8812  NaN  NaN  11
4        8813   82  NaN  15

1

my_df = pd.DataFrame.from_dict(my_dict, orient='index', columns=['my_col'])

.. सही तरीके से डिसाइड किया होगा (प्रत्येक डिफरेंट की को एक अलग df कॉलम में डालकर, और df पंक्तियों में प्रमुख मान), इसलिए पहली बार में डक्ट्स एक ही कॉलम में स्क्वैश नहीं होंगे।


0

मैंने उन चरणों को एक विधि में समाप्‍त कर दिया है, आपको केवल डेटाफ्रेम और कॉलम को पास करना होगा जिसमें विस्तार करने के लिए तानाशाही है:

def expand_dataframe(dw: pd.DataFrame, column_to_expand: str) -> pd.DataFrame:
    """
    dw: DataFrame with some column which contain a dict to expand
        in columns
    column_to_expand: String with column name of dw
    """
    import pandas as pd

    def convert_to_dict(sequence: str) -> Dict:
        import json
        s = sequence
        json_acceptable_string = s.replace("'", "\"")
        d = json.loads(json_acceptable_string)
        return d    

    expanded_dataframe = pd.concat([dw.drop([column_to_expand], axis=1),
                                    dw[column_to_expand]
                                    .apply(convert_to_dict)
                                    .apply(pd.Series)],
                                    axis=1)
    return expanded_dataframe

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