2017-05-13 8 views
2

私は "flatten"したい辞書の大きい(ish)Seriesを持っています。一連の辞書をDataFrameに効率的に変換する

>>> my_series = pd.Series([{'A': [1], 'B' : []}, {'A' : [1, 2], 'B' : [3, 4]}]) 
>>> my_series 
0   {u'A': [1], u'B': []} 
1 {u'A': [1, 2], u'B': [3, 4]} 
dtype: object 

次のステップは、階層的なインデックスを持つ「DATAFRAME」に変換されています。テストするために/私は同様の構造でSeriesを作成している私の問題を再現私は、機能的に動作する方法を発見した:これは私が欲しいものを私に与え

>>> pd.DataFrame(pd.DataFrame.from_dict(row, orient='index').stack() for row in my_series) 
    A   B  
    0 1 0 1 
0 1.0 NaN NaN NaN 
1 1.0 2.0 3.0 4.0 

を、私の実際のデータセットで、それはリストのそれぞれに0-4要素と3万行のために約60秒を取って、法外遅いです、およそ8GのRAMを使用しています。

私はmultiprocessingモジュールで並列処理を使って試してみましたが、もっと速い方法があるかどうかここで尋ねると思いました。

もっと合理的な時間に上記と同じ結果を達成することはできますか?

+0

@Kasramvd - 先端に感謝:) – arman

答えて

1

あなたはDataFrameコンストラクタを使用することができますが、最初にlistに続いvaluesによってSeriesnumpy arrayに変換し、:

a = pd.DataFrame(my_series.values.tolist()) 
print (a) 
     A  B 
0  [1]  [] 
1 [1, 2] [3, 4] 

その後flatennigためlist comprehensionで可能な使用concatです:

は、
b = pd.concat([pd.DataFrame(a[x].values.tolist()) for x in a.columns], axis=1,keys=a.columns) 
print (b) 
    A   B  
    0 1 0 1 
0 1 NaN NaN NaN 
1 1 2.0 3.0 4.0 

配列をnumpyのための変換がある場合の方が高速です:

In [93]: %timeit pd.DataFrame(list(my_series)) 
1000 loops, best of 3: 550 µs per loop 

In [94]: %timeit pd.DataFrame(my_series.values.tolist()) 
1000 loops, best of 3: 516 µs per loop 
+0

私は本当に理由を理解できませんが、このトリックは時間を数分から1秒未満に短縮しました。乾杯。 – arman

1

まず、パンダベースのデータ構造に辞書があるので、シリーズの代わりにDataFrameを作成することができます。

第2にDataFrameは、辞書のリストを受け入れ、あなたのために期待される結果を構築することができます。だから、あなたが最初の場所で、一連の建設を制御することはできません場合は、あなただけのリストとDataFrameにそれを渡すために直列に変換することができます:

In [10]: pd.DataFrame(list(my_series)) 
Out[10]: 
     A  B 
0  [1]  [] 
1 [1, 2] [3, 4] 
0

セットアップ

my_series = pd.Series([{'A': [1], 'B' : []}, {'A' : [1, 2], 'B' : [3, 4]}]) 
df = pd.DataFrame.from_dict(s.tolist()) 

ソリューション

[OK]を、より高速なソリューションの作業を得ました。

idx = pd.MultiIndex.from_product([['A','B'],[0,1]]) 

pd.DataFrame(pd.DataFrame(df.values.flatten().tolist()).values.reshape(2,-1), columns=idx) 

Out[1051]: 
    A   B  
    0 1 0 1 
0 1.0 NaN NaN NaN 
1 1.0 2.0 3.0 4.0 

旧ソリューション私はそれを構築したかどうかはわかりませんが、私はこれになります

#Convert list elements to columns 
df_A = df.A.apply(pd.Series).stack().unstack() 
df_B = df.B.apply(pd.Series).stack().unstack() 
#rename columns 
df_A.columns = ['A_' + str(e) for e in df_A.columns] 
df_B.columns = ['B_' + str(e) for e in df_B.columns] 
#combine two dataframes 
pd.concat([df_A,df_B],axis=1) 

Out[973]: 
    A_0 A_1 B_0 B_1 
0 1.0 NaN NaN NaN 
1 1.0 2.0 3.0 4.0 

テスト

%timeit pd.DataFrame(pd.DataFrame(df.values.flatten().tolist()).values.reshape(2,-1), columns=idx) 
1000 loops, best of 3: 378 µs per loop 

%timeit pd.concat([pd.DataFrame(df[x].values.tolist()) for x in df.columns], axis=1,keys=df.columns) 
1000 loops, best of 3: 1.22 ms per loop 
+0

ありがとうJezrael。 – Allen

+0

はい、しかし、常に '2'列はありますか?また、OPはMultiIndexを列に入れたいと考えていますが、どう思いますか? – jezrael

+0

2列以上の場合は、reshape()を変更すると効果があります。 Multiindexを見てみましょう – Allen

関連する問題