একটি পান্ডা কলামের ভিতরে আলাদা কলামগুলিতে অভিধান / তালিকা বিভক্ত করা


146

আমি পোস্টগ্রিজ এসকিউএল ডাটাবেসে ডেটা সংরক্ষণ করেছি। আমি পাইথন 2.7 ব্যবহার করে এই ডেটাটি অনুসন্ধান করছি এবং এটিকে একটি পান্ডাস ডেটা ফ্রেমে পরিণত করছি। যাইহোক, এই ডেটাফ্রেমের শেষ কলামটির মধ্যে মানগুলির একটি অভিধান (বা তালিকা?) রয়েছে। ডেটাফ্রেমটি দেখতে এমন দেখাচ্ছে:

[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"}

আমাকে এই কলামটি পৃথক কলামে বিভক্ত করতে হবে যাতে ডেটা ফ্রেমটি দেখতে এই রকম হয়:

[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)

আমি গত সপ্তাহে এই কোডটি চালাচ্ছিলাম এবং এটি ভাল কাজ করছিল was তবে এখন আমার কোডটি নষ্ট হয়ে গেছে এবং আমি লাইন থেকে এই ত্রুটি পেয়েছি [4]:

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

আমি কোডটিতে কোনও পরিবর্তন করি নি তবে এখন ত্রুটিটি পাচ্ছি। আমি মনে করি এটি আমার পদ্ধতিটি দৃ rob় বা সঠিক না হওয়ার কারণে to

তালিকার এই কলামটি পৃথক কলামে কীভাবে বিভক্ত করা যায় সে সম্পর্কে কোনও পরামর্শ বা নির্দেশনা প্রশংসিত হবে!

সম্পাদনা: আমি মনে করি .টোলিস্ট () এবং। অ্যাপ্লিকেশন পদ্ধতিগুলি আমার কোডে কাজ করছে না কারণ এটি একটি ইউনিকোড স্ট্রিং, যেমন:

#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অংশ
Joris

এটির একটি অংশ যা iloc[:, :3]ধরে নিয়েছে যে সেখানে 3 টি আইটেম থাকবে এবং সম্ভবত সাম্প্রতিক ডেটা স্লাইসের মধ্যে কেবল 1 বা 2 রয়েছে (উদাহরণস্বরূপ এমনটি হবে bনা index 8813)?
ডোয়ান্ডারসন

উত্তর:


166

স্ট্রিংটিকে আসল ডিকে রূপান্তর করতে, আপনি এটি করতে পারেন 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 ',' বি ':' 2 ',' সি ':' 3 '} এবং {u'a': '1', u'b ':' 2 ', u'c ':' 3 'your যেমন আপনার সমাধানগুলি দেখায়। সুতরাং কোডটি 3 টি স্বীকৃত কলামগুলিতে বিভক্ত করতে পারে না।
llaffin

2
@ ইয়াহান আসলে, এটি পরীক্ষা করে দেখুন এবং প্রয়োগটি DataFrame(df['col'].tolist())প্রয়োগের পদ্ধতির চেয়ে কিছুটা দ্রুত!
জুরিস

3
@llaffin যদি একটি স্ট্রিং, আপনি একটি প্রকৃত অভি যে রূপান্তর করতে পারেন সঙ্গে df[col].map(eval)এটি একটি DataFrame রূপান্তর সামনে
Joris

2
নিখুঁত কাজ করে, কিন্তু (অনেক) নতুন সমাধান (2019) দ্বারা লেচ Birek অবদান তুলনায় ধীর হয় stackoverflow.com/a/55355928/2721710
drasc

85

আমি জানি প্রশ্নটি বেশ পুরানো, তবে আমি এখানে উত্তর খুঁজে পেয়েছি। এটি ব্যবহার করে এখন আরও একটি ভাল (এবং দ্রুত) উপায় রয়েছে json_normalize:

import pandas as pd

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

এটি ব্যয়বহুল প্রয়োগের ক্রিয়াগুলি এড়ায় ...


4
কি দারুন! আমি JSON অবজেক্টগুলিতে পান্ডাসে সারাদিন ক্লান্তিকর এবং বিভ্রান্তিকর প্রয়োগগুলি সম্পাদন করে চলেছি এবং তারপরে আমি এই উত্তরে হোঁচট খেয়েছি এবং ভেবেছিলাম "উপায় নেই, এটি এত সহজ হতে পারত না!" তারপরে আমি এটি চেষ্টা করেছিলাম এবং এটি ছিল। অনেক ধন্যবাদ!
ইমাক

এখানে কেবল সমস্যাটি হ'ল এটি জসন ছাড়া অন্য কলামগুলিতে অনুলিপি করে দেখা যাচ্ছে না, এর অর্থ আপনি যদি জসন মানগুলির এক সারিকে স্বাভাবিক করার চেষ্টা করছেন তবে আপনাকে এটি অনুলিপি করতে হবে এবং দুটি সংযুক্ত করতে হবে, এখনও আমার পুনরাবৃত্তির চেয়ে অনেক ভাল পদ্ধতি। Cudos!
মিঃ ড্রিউ

এই সমাধানের জন্য কীভাবে কলামগুলির স্বাভাবিককরণের প্রয়োজন তার তালিকাটি গতিশীলভাবে নির্বাচন করা সম্ভব হবে? .jsonফাইলগুলি থেকে যে লেনদেনের ডেটা আমি নিয়ে আসছি তা বিভিন্ন উত্স থেকে আসছে এবং এটি সর্বদা একই কলামগুলিতে বাসা বাঁধে না। আমি কলামগুলির একটি তালিকা তৈরি করার একটি উপায় সন্ধান করার চেষ্টা করেছি যা এতে ডিকট রয়েছে তবে এটি কার্যকর হবে বলে মনে হচ্ছে না
কলম স্মিথ

5
from pandas.io.json import json_normalize
রামিন মেলিকভ

চূড়ান্ত কলামগুলিতে উপসর্গ প্রয়োগ করার কোনও উপায় আছে কি? আমি লক্ষ্য করেছি meta_prefixএবং এর মতো যুক্তি রয়েছে record_prefix। যদিও, আমি আমার ডেটাফ্রেম দিয়ে সেই কাজটি করতে পারি না (চূড়ান্ত ডাটাফ্রেমটি আমার ক্ষেত্রে সঠিক তবে আমি উপসর্গগুলি প্রয়োগ করতে চাই)।
জে স্নো

21

এটি ব্যবহার করে দেখুন: এসকিউএল থেকে ফিরে আসা ডেটাগুলিকে একটি ডিক্টে রূপান্তর করতে হবে। বা এটি "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

আমি পদ্ধতিটি দৃ Pol়ভাবে সুপারিশ করি 'দূষণকারী' কলামটি বের করুন:

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

এটা তুলনায় অনেক দ্রুত

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

যখন ডিএফের আকারটি বিশাল হয়।


দুর্দান্ত / যদি আপনি কীভাবে / কেন এটি কাজ করে এবং এত বেশি ভাল তা ব্যাখ্যা করতে পারতেন! আমার জন্য এটি সর্বদা দ্রুত এবং একবারে আপনি ~ 1000 সারি বেশি পেয়ে গেলে ~ 200 গুণ দ্রুত
স্যাম ম্যাসন

@ স্যামমাসন যখন আপনি 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'])

.. ডিকটি সঠিকভাবে পার্স করা উচিত (প্রতিটি ডিক কী একটি পৃথক ডিএফ কলামে এবং কী মানগুলি ডিএফ সারিগুলিতে স্থাপন করা), সুতরাং ডিক্সটি প্রথম স্থানে একটি একক কলামে স্কোয়াশ হতে না পারে।


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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.