如何处理在每个单元格中都有一个字典列表的熊猫列

Jam*_*mes 6 pytables python-2.7 pandas hdfstore

我有一个 DataFrame,其中包含一个列,其中每个单元格都由一个 dicts 列表组成,并且每个 dicts 列表的长度不同(包括 0)。

一个例子:

df = pd.DataFrame({'ID' : [13423,294847,322844,429847], 'RANKS': [[{u'name': u'A', u'price': u'$1.00', u'rank': u'1'},
{u'name': u'B', u'price': u'$4.00', u'rank': u'2'},
{u'name': u'C', u'price': u'$3.99', u'rank': u'3'},
{u'name': u'D', u'price': u'$2.00', u'rank': u'4'},
{u'name': u'E', u'price': u'$2.50', u'rank': u'5'}],

[{u'name': u'AA', u'price': u'$1.99', u'rank': u'1'},
{u'name': u'BB', u'price': u'$6.99', u'rank': u'2'}],

[{u'name': u'Z', u'price': u'$0.99', u'rank': u'1'},
{u'name': u'Y', u'price': u'$10.00', u'rank': u'2'},
{u'name': u'X', u'price': u'$1.99', u'rank': u'3'}],[]], 'count' : [5,2,3,0]})
Run Code Online (Sandbox Code Playgroud)

请注意,“count”是“RANKS”中的字典数。我的目标是创建一系列额外的数据帧/表(每个“等级”一个)并将它们链接到 HDFStore 中的主表。就像是:

Rank_2
ID       Price   Name
13423    $4.00    B  
294847   $6.99    BB 
322844   $10.99   Y 
429847   NaN      NaN   


Rank_3
ID       Price   Name
13423    $3.99    C  
294847   NaN      NaN 
322844   $1.99    X 
429847   NaN      NaN   
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以在需要时轻松查询 ID 和排名,但主表不会因分层数据的展开而变得混乱。

但是,问题是我无法弄清楚如何从此列创建 DataFrame。我已经尝试了很多事情,第一个(如果有效,则嵌套在 for 循环中,但当然没有):

Rank_1 = pd.DataFrame(df.loc[df['count'] > 0]['RANKS'].map(lambda x: pd.DataFrame(x[0])))
Run Code Online (Sandbox Code Playgroud)

其次,因为价格对我来说是最重要的部分:

for i in range(0,5):
    df['rank_%s' % str(i+1)] = df[df['count'] > i]['RANKS'].map(lambda x: x[i]['price'].strip('$'))
Run Code Online (Sandbox Code Playgroud)

然后转换为浮动。这行得通,但这是一个相当大的妥协。有没有一种有效的方法(不会挂在 NaN 上)来实现我为每个等级设置单独 DataFrame 的目标?

unu*_*tbu 6

我的直觉反应是,您可能不应该将 DataFrame 分解成许多较小的 DataFrame。处理大量小型 DataFrame 需要一个 Python 循环,这通常是通往缓慢之路的一步。相反,我认为您可能会更好地使用一个 DataFrame,它会展平 dict 列表,以便每个内部 dict 在 DataFrame 中都有自己的行。内部字典的键将成为新列。我怀疑这种单一的平面 DataFrame 格式可以做任何多 DataFrame 替代品可以做的事情,但速度更快,并且它可以使保存到 HDFStore 变得简单。

假设您有一个 DataFrame,其中列中有一个 dicts 列表RANKS

import numpy as np
import pandas as pd

df = pd.DataFrame({'ID' : [13423,294847,322844,429847], 'RANKS': [[{u'name': u'A', u'price': u'$1.00', u'rank': u'1'},
{u'name': u'B', u'price': u'$4.00', u'rank': u'2'},
{u'name': u'C', u'price': u'$3.99', u'rank': u'3'},
{u'name': u'D', u'price': u'$2.00', u'rank': u'4'},
{u'name': u'E', u'price': u'$2.50', u'rank': u'5'}],

[{u'name': u'AA', u'price': u'$1.99', u'rank': u'1'},
{u'name': u'BB', u'price': u'$6.99', u'rank': u'2'}],

[{u'name': u'Z', u'price': u'$0.99', u'rank': u'1'},
{u'name': u'Y', u'price': u'$10.00', u'rank': u'2'},
{u'name': u'X', u'price': u'$1.99', u'rank': u'3'}],[]], 'count' : [5,2,3,0]})
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样构建一个每行一个字典的平面 DataFrame:

result = []
for idx, row in df.iterrows():
    for dct in row['RANKS']:
        dct['ID'] = row['ID']
        dct['count'] = row['count']
        result.append(dct)
del df
result = pd.DataFrame(result)
result['rank'] = result['rank'].astype(np.int32)
result['price'] = result['price'].str.replace('$', '')
result['price'] = result['price'].astype('float')
print(result)
Run Code Online (Sandbox Code Playgroud)

这产生

       ID  count name  price  rank
0   13423      5    A   1.00     1
1   13423      5    B   4.00     2
2   13423      5    C   3.99     3
3   13423      5    D   2.00     4
4   13423      5    E   2.50     5
5  294847      2   AA   1.99     1
6  294847      2   BB   6.99     2
7  322844      3    Z   0.99     1
8  322844      3    Y  10.00     2
9  322844      3    X   1.99     3
Run Code Online (Sandbox Code Playgroud)

请注意,result直接从原始数据源构建(因此df完全避免)将是一个更干净、内存需求更少的解决方案。