有效地将一系列字典转换为DataFrame

时间:2017-05-13 08:11:12

标签: python performance pandas

我有一个很大的(ish)Series字典,我想“扁平化”。为了测试/重现我的问题,我创建了一个具有类似结构的Series

>>> 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”。我找到了一种功能正常的方法:

>>> 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个元素的30,000行大约需要60秒,并使用大约8G的RAM。

我尝试使用map模块进行并行multiprocessing操作来加快速度,但我想在此问一下是否有更好的方法。

我可以在更合理的时间内取得与上述相同的结果吗?

3 个答案:

答案 0 :(得分:1)

首先,由于您的词典位于基于熊猫的数据结构中,因此您可以创建DataFrame而不是系列。

其次DataFrame可以接受字典列表并为您构建预期结果。因此,如果您首先无法控制系列的构建,则只需将系列转换为列表并将其传递给DataFrame

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

答案 1 :(得分:1)

您可以使用DataFrame构造函数,但首先将Series转换为numpy array values再转换为list

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

然后,对于flatennig,可以使用concatlist comprehension

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

答案 2 :(得分:0)

<强>设置

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

<强>解决方案

好的,有一个更快的解决方案。

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