我有一个像这样的数据框:
matrix = [(222, {'a': 1, 'b':3, 'c':2, 'd':1}),
(333, {'a': 1, 'b':0, 'c':0, 'd':1})]
df = pd.DataFrame(matrix, columns=['ordernum', 'dict_of item_counts'])
ordernum dict_of item_counts
0 222 {'a': 1, 'b': 3, 'c': 2, 'd': 1}
1 333 {'a': 1, 'b': 0, 'c': 0, 'd': 1}
并且我想创建一个数据帧,其中每个
ordernum
对于dict_of_item_counts
中不为0的每个字典键重复。我还想创建一个key
列来显示该行相应的字典键以及包含字典值的 value
列。最后,我还需要一个 ordernum_index
来计算每个 ordernum
数据框中的不同行。
最终的数据框应如下所示:
ordernum ordernum_index key value
222 1 a 1
222 2 b 3
222 3 c 2
222 4 d 1
333 1 a 1
333 2 d 1
任何帮助将不胜感激:)
始终尝试构建数据,可以轻松完成,如下所示:
>>> matrix
[(222, {'a': 1, 'b': 3, 'c': 2, 'd': 1}), (333, {'a': 1, 'b': 0, 'c': 0, 'd': 1})]
>>> data = [[item[0]]+[i+1]+list(value) for item in matrix for i,value in enumerate(item[1].items()) if value[-1]!=0]
>>> data
[[222, 1, 'a', 1], [222, 2, 'b', 3], [222, 3, 'c', 2], [222, 4, 'd', 1], [333, 1, 'a', 1], [333, 4, 'd', 1]]
>>> pd.DataFrame(data, columns=['ordernum', 'ordernum_index', 'key', 'value'])
ordernum ordernum_index key value
0 222 1 a 1
1 222 2 b 3
2 222 3 c 2
3 222 4 d 1
4 333 1 a 1
5 333 4 d 1
apply
和 pd.Series
来扩展字典,并使用 concat
将其连接到其他列 (ordernum)。请参阅下文了解 df2
的中间结果。
现在要将每一列变成一行,请使用 melt
,然后使用 query
删除所有 0 行,最后使用 assign
cumcount
获取索引(订购后) ) 并加 1 从 1 开始计数,而不是 0。
df2 = pd.concat([df[['ordernum']], df['dict_of item_counts'].apply(pd.Series)], axis=1)
(df2.melt(id_vars='ordernum', var_name='key')
.query('value != 0')
.sort_values(['ordernum', 'key'])
.assign(ordernum_index = lambda df: df.groupby('ordernum').cumcount().add(1)))
# ordernum key value ordernum_index
#0 222 a 1 1
#2 222 b 3 2
#4 222 c 2 3
#6 222 d 1 4
#1 333 a 1 1
#7 333 d 1 2
现在 df2 看起来像:
# ordernum a b c d
#0 222 1 3 2 1
#1 333 1 0 0 1
iterrows
访问它们并从 ordernum, key, value
创建一个元组来完成此操作。
最后,为了创建您的
ordernum_index
,我们在 ordernum
上进行分组并执行 cumcount
:
data = [(r['ordernum'], k, v) for _, r in df.iterrows() for k, v in r['dict_of item_counts'].items() ]
new = pd.DataFrame(data, columns=['ordernum', 'key', 'value']).sort_values('ordernum').reset_index(drop=True)
new['ordernum_index'] = new[new['value'].ne(0)].groupby('ordernum').cumcount().add(1)
new.dropna(inplace=True)
ordernum key value ordernum_index
0 222 a 1 1.0
1 222 b 3 2.0
2 222 c 2 3.0
3 222 d 1 4.0
4 333 a 1 1.0
7 333 d 1 2.0
使用
df1
作为值,使用 df['dict_of item_counts'].tolist()
作为索引构建数据框 df.ordernum
。 replace
0 与 np.nan
和 stack
与 dropna=True 忽略 0 值。 reset_index
获取所有列。
接下来,使用
ordernum_index
和 groupby
创建列 cumcount
。
最后,将列名更改为合适的名称。
df1 = pd.DataFrame(df['dict_of item_counts'].tolist(), index=df.ordernum).replace(0, np.nan).stack(dropna=True).reset_index(name='value')
df1['ordernum_index'] = df1.groupby('ordernum')['value'].cumcount() + 1
df1 = df1.rename(columns={'level_1': 'key'})
Out[732]:
ordernum key value ordernum_index
0 222 a 1.0 1
1 222 b 3.0 2
2 222 c 2.0 3
3 222 d 1.0 4
4 333 a 1.0 1
5 333 d 1.0 2
dd1=df1.set_index("ordernum").dict_of2item_counts.map(eval).apply(pd.Series).stack().reset_index().rename(columns={'level_1':"key",0:"value"}).query("value>0")
dd1.assign(ordernum_index=dd1.groupby("ordernum").key.transform('rank',method='first').astype(int))
ordernum key value ordernum_index
0 222 a 1 1
1 222 b 3 2
2 222 c 2 3
3 222 d 1 4
4 333 a 1 1
7 333 d 1 2