2014-12-03 4 views
51

मेरे पास डेटाफ़्रेम है जहां कुछ कक्षों में एकाधिक मानों की सूचियां होती हैं। किसी सेल में एकाधिक मानों को संग्रहीत करने के बजाय, मैं डेटाफ्रेम का विस्तार करना चाहता हूं ताकि सूची में प्रत्येक आइटम अपनी पंक्ति प्राप्त कर सके (सभी अन्य कॉलमों में समान मानों के साथ)। तो अगर मेरे पास है:पांडा: जब सेल सामग्री सूचीबद्ध होती है, तो सूची में प्रत्येक तत्व के लिए एक पंक्ति बनाएं

import pandas as pd 
import numpy as np 

df = pd.DataFrame(
    {'trial_num': [1, 2, 3, 1, 2, 3], 
    'subject': [1, 1, 1, 2, 2, 2], 
    'samples': [list(np.random.randn(3).round(2)) for i in range(6)] 
    } 
) 

df 
Out[10]: 
       samples subject trial_num 
0 [0.57, -0.83, 1.44]  1   1 
1 [-0.01, 1.13, 0.36]  1   2 
2 [1.18, -1.46, -0.94]  1   3 
3 [-0.08, -4.22, -2.05]  2   1 
4  [0.72, 0.79, 0.53]  2   2 
5 [0.4, -0.32, -0.13]  2   3 

मैं लंबे समय से फार्म के लिए कैसे कन्वर्ट करते हैं, उदाहरण के लिए:

subject trial_num sample sample_num 
0  1   1 0.57   0 
1  1   1 -0.83   1 
2  1   1 1.44   2 
3  1   2 -0.01   0 
4  1   2 1.13   1 
5  1   2 0.36   2 
6  1   3 1.18   0 
# etc. 

सूचकांक नहीं है महत्वपूर्ण है, यह ठीक मौजूदा सूचकांक और अंतिम आदेश प्रतिसाद नहीं के रूप में कॉलम स्थापित करने के लिए है टी महत्वपूर्ण है।

उत्तर

59

एक लंबे समय तक सा मेरी अपेक्षा से:

>>> df 
       samples subject trial_num 
0 [-0.07, -2.9, -2.44]  1   1 
1 [-1.52, -0.35, 0.1]  1   2 
2 [-0.17, 0.57, -0.65]  1   3 
3 [-0.82, -1.06, 0.47]  2   1 
4 [0.79, 1.35, -0.09]  2   2 
5 [1.17, 1.14, -1.79]  2   3 
>>> 
>>> s = df.apply(lambda x: pd.Series(x['samples']),axis=1).stack().reset_index(level=1, drop=True) 
>>> s.name = 'sample' 
>>> 
>>> df.drop('samples', axis=1).join(s) 
    subject trial_num sample 
0  1   1 -0.07 
0  1   1 -2.90 
0  1   1 -2.44 
1  1   2 -1.52 
1  1   2 -0.35 
1  1   2 0.10 
2  1   3 -0.17 
2  1   3 0.57 
2  1   3 -0.65 
3  2   1 -0.82 
3  2   1 -1.06 
3  2   1 0.47 
4  2   2 0.79 
4  2   2 1.35 
4  2   2 -0.09 
5  2   3 1.17 
5  2   3 1.14 
5  2   3 -1.79 

आप अनुक्रमिक सूचकांक चाहते हैं, आप परिणाम को reset_index(drop=True) आवेदन कर सकते हैं।

अद्यतन:

>>> res = df.set_index(['subject', 'trial_num'])['samples'].apply(pd.Series).stack() 
>>> res = res.reset_index() 
>>> res.columns = ['subject','trial_num','sample_num','sample'] 
>>> res 
    subject trial_num sample_num sample 
0   1   1   0 1.89 
1   1   1   1 -2.92 
2   1   1   2 0.34 
3   1   2   0 0.85 
4   1   2   1 0.24 
5   1   2   2 0.72 
6   1   3   0 -0.96 
7   1   3   1 -2.72 
8   1   3   2 -0.11 
9   2   1   0 -1.33 
10  2   1   1 3.13 
11  2   1   2 -0.65 
12  2   2   0 0.10 
13  2   2   1 0.65 
14  2   2   2 0.15 
15  2   3   0 0.64 
16  2   3   1 -0.10 
17  2   3   2 -0.76 
+0

धन्यवाद, यहां तक ​​कि पहला कदम प्रत्येक आइटम को अपने कॉलम में लाने के लिए आवेदन करना एक बड़ी मदद है। मैं इसे करने के लिए थोड़ा अलग तरीके से आने में सक्षम था, लेकिन अभी भी कुछ उचित कदम शामिल हैं। स्पष्ट रूप से यह पांडस में करने के लिए सीधा नहीं है! – Marius

+0

ग्रेट उत्तर। आप 'df.apply (lambda x: pd.Series (x ['samples']), axis = 1) को 'df.samples.apply (pd.Series)' के साथ बदलकर इसे छोटा कर सकते हैं। –

4

रोमन Pekar के समाधान कदम-दर-कदम यह बेहतर समझने के लिए के माध्यम से काम करने के लिए कोशिश कर रहा है, मैं अपने ही समाधान है, जो melt का उपयोग करता है भ्रामक स्टैकिंग के कुछ से बचने के लिए के साथ आया था और सूचकांक रीसेटिंग। मैं नहीं कह सकता कि यह स्पष्ट रूप से है एक स्पष्ट समाधान हालांकि:

items_as_cols = df.apply(lambda x: pd.Series(x['samples']), axis=1) 
# Keep original df index as a column so it's retained after melt 
items_as_cols['orig_index'] = items_as_cols.index 

melted_items = pd.melt(items_as_cols, id_vars='orig_index', 
         var_name='sample_num', value_name='sample') 
melted_items.set_index('orig_index', inplace=True) 

df.merge(melted_items, left_index=True, right_index=True) 

आउटपुट (जाहिर है हम मूल नमूने कॉलम अब छोड़ सकते हैं):

    samples subject trial_num sample_num sample 
0 [1.84, 1.05, -0.66]  1   1   0 1.84 
0 [1.84, 1.05, -0.66]  1   1   1 1.05 
0 [1.84, 1.05, -0.66]  1   1   2 -0.66 
1 [-0.24, -0.9, 0.65]  1   2   0 -0.24 
1 [-0.24, -0.9, 0.65]  1   2   1 -0.90 
1 [-0.24, -0.9, 0.65]  1   2   2 0.65 
2 [1.15, -0.87, -1.1]  1   3   0 1.15 
2 [1.15, -0.87, -1.1]  1   3   1 -0.87 
2 [1.15, -0.87, -1.1]  1   3   2 -1.10 
3 [-0.8, -0.62, -0.68]  2   1   0 -0.80 
3 [-0.8, -0.62, -0.68]  2   1   1 -0.62 
3 [-0.8, -0.62, -0.68]  2   1   2 -0.68 
4 [0.91, -0.47, 1.43]  2   2   0 0.91 
4 [0.91, -0.47, 1.43]  2   2   1 -0.47 
4 [0.91, -0.47, 1.43]  2   2   2 1.43 
5 [-1.14, -0.24, -0.91]  2   3   0 -1.14 
5 [-1.14, -0.24, -0.91]  2   3   1 -0.24 
5 [-1.14, -0.24, -0.91]  2   3   2 -0.91 
5

आप भी इस के लिए pd.concat और pd.melt उपयोग कर सकते हैं:

>>> objs = [df, pd.DataFrame(df['samples'].tolist())] 
>>> pd.concat(objs, axis=1).drop('samples', axis=1) 
    subject trial_num  0  1  2 
0  1   1 -0.49 -1.00 0.44 
1  1   2 -0.28 1.48 2.01 
2  1   3 -0.52 -1.84 0.02 
3  2   1 1.23 -1.36 -1.06 
4  2   2 0.54 0.18 0.51 
5  2   3 -2.18 -0.13 -1.35 
>>> pd.melt(_, var_name='sample_num', value_name='sample', 
...   value_vars=[0, 1, 2], id_vars=['subject', 'trial_num']) 
    subject trial_num sample_num sample 
0   1   1   0 -0.49 
1   1   2   0 -0.28 
2   1   3   0 -0.52 
3   2   1   0 1.23 
4   2   2   0 0.54 
5   2   3   0 -2.18 
6   1   1   1 -1.00 
7   1   2   1 1.48 
8   1   3   1 -1.84 
9   2   1   1 -1.36 
10  2   2   1 0.18 
11  2   3   1 -0.13 
12  1   1   2 0.44 
13  1   2   2 2.01 
14  1   3   2 0.02 
15  2   1   2 -1.06 
16  2   2   2 0.51 
17  2   3   2 -1.35 

आखिरी, यदि आपको आवश्यकता है तो पहले पहले तीन कॉलम पर आधार को सॉर्ट कर सकते हैं।

+0

यह केवल तभी काम करता है यदि आप प्राथमिकता जानते हैं कि सूचियों की लंबाई क्या होगी और/या यदि वे सभी एक ही लंबाई में होंगी? – Chill2Macht

3

कि मैनुअल स्तंभ नामकरण से बचा जाता है रोमन Pekar के जवाब का एक संस्करण की तलाश में उन लोगों के लिए:

column_to_explode = 'samples' 
res = (df 
     .set_index([x for x in df.columns if x != column_to_explode])[column_to_explode] 
     .apply(pd.Series) 
     .stack() 
     .reset_index()) 
res = res.rename(columns={ 
      res.columns[-2]:'exploded_{}_index'.format(column_to_explode), 
      res.columns[-1]: '{}_exploded'.format(column_to_explode)}) 
1
lst_col = 'samples' 

r = pd.DataFrame({ 
     col:np.repeat(df[col].values, df[lst_col].str.len()) 
     for col in df.columns.drop(lst_col)} 
    ).assign(**{lst_col:np.concatenate(df[lst_col].values)})[df.columns] 

परिणाम:

In [103]: r 
Out[103]: 
    samples subject trial_num 
0  0.10  1   1 
1  -0.20  1   1 
2  0.05  1   1 
3  0.25  1   2 
4  1.32  1   2 
5  -0.17  1   2 
6  0.64  1   3 
7  -0.22  1   3 
8  -0.71  1   3 
9  -0.03  2   1 
10 -0.65  2   1 
11  0.76  2   1 
12  1.77  2   2 
13  0.89  2   2 
14  0.65  2   2 
15 -0.98  2   3 
16  0.65  2   3 
17 -0.30  2   3 

पुनश्च here you may find a bit more generic solution

संबंधित मुद्दे