从字典创建 Pandas 数据框架

19

我有一个Python字典,记录了用户对商品的评分,看起来大致如下:

sample={'user1': {'item1': 2.5, 'item2': 3.5, 'item3': 3.0, 'item4': 3.5, 'item5': 2.5, 'item6': 3.0}, 
'user2': {'item1': 2.5, 'item2': 3.0, 'item3': 3.5, 'item4': 4.0}, 
'user3': {'item2':4.5,'item5':1.0,'item6':4.0}}

我想把它转换成一个类似于pandas数据框的结构

     col1   col2  col3
0   user1  item1   2.5
1   user1  item2   3.5
2   user1  item3   3.0
3   user1  item4   3.5
4   user1  item5   2.5
5   user1  item6   3.0
6   user2  item1   2.5
7   user2  item2   3.0
8   user2  item3   3.5
9   user2  item4   4.0
10  user3  item2   4.5
11  user3  item5   1.0
12  user3  item6   4.0

非常感谢任何想法 :)

5个回答

19

请尝试以下代码:

import pandas

sample={'user1': {'item1': 2.5, 'item2': 3.5, 'item3': 3.0, 'item4': 3.5, 'item5': 2.5, 'item6': 3.0},
        'user2': {'item1': 2.5, 'item2': 3.0, 'item3': 3.5, 'item4': 4.0},
        'user3': {'item2':4.5,'item5':1.0,'item6':4.0}}

df = pandas.DataFrame([
    [col1,col2,col3] for col1, d in sample.items() for col2, col3 in d.items()
])

1
很好,但如何反对这个任务。即如果给定数据框,如何将其转换为字典。另外,如果列被随机打乱了呢? - SujitS
1
@BlackRabbitt,使用默认字典from collections import defaultdict; d = defaultdict(dict); for user, item, value in df.values: d.setdefault(user, {})[item] = value - falsetru
1
@SujitS 还有 .to_dict(),可以使用 df.to_dict() - danodonovan

13

我认为你需要执行的操作——将表格转换为非透视形式——被称为“melting”(也叫“长格式化”)。在这种情况下,通过使用pd.melt函数可以完成大部分难点,其余即为重命名和重新排列:

df = pd.DataFrame(sample).reset_index().rename(columns={"index": "item"})
df = pd.melt(df, "item", var_name="user").dropna()
df = df[["user", "item", "value"]].reset_index(drop=True)

仅仅调用DataFrame会生成我们想要的信息,但是形状不正确:

>>> df = pd.DataFrame(sample)
>>> df
       user1  user2  user3
item1    2.5    2.5    NaN
item2    3.5    3.0    4.5
item3    3.0    3.5    NaN
item4    3.5    4.0    NaN
item5    2.5    NaN    1.0
item6    3.0    NaN    4.0

那么我们将索引提升为一个真正的列,并改进名称:

>>> df = pd.DataFrame(sample).reset_index().rename(columns={"index": "item"})
>>> df
    item  user1  user2  user3
0  item1    2.5    2.5    NaN
1  item2    3.5    3.0    4.5
2  item3    3.0    3.5    NaN
3  item4    3.5    4.0    NaN
4  item5    2.5    NaN    1.0
5  item6    3.0    NaN    4.0

然后我们可以调用 pd.melt 来转换列。如果我们没有指定我们想要的变量名 "user",它就会给它一个无聊的名称 "variable"(就像它给数据本身起的无聊名称 "value" 一样)。

>>> df = pd.melt(df, "item", var_name="user").dropna()
>>> df
     item   user  value
0   item1  user1    2.5
1   item2  user1    3.5
2   item3  user1    3.0
3   item4  user1    3.5
4   item5  user1    2.5
5   item6  user1    3.0
6   item1  user2    2.5
7   item2  user2    3.0
8   item3  user2    3.5
9   item4  user2    4.0
13  item2  user3    4.5
16  item5  user3    1.0
17  item6  user3    4.0

最后,我们可以重新排列和重新编号索引:

>>> df = df[["user", "item", "value"]].reset_index(drop=True)
>>> df
     user   item  value
0   user1  item1    2.5
1   user1  item2    3.5
2   user1  item3    3.0
3   user1  item4    3.5
4   user1  item5    2.5
5   user1  item6    3.0
6   user2  item1    2.5
7   user2  item2    3.0
8   user2  item3    3.5
9   user2  item4    4.0
10  user3  item2    4.5
11  user3  item5    1.0
12  user3  item6    4.0

melt 很实用,一旦你习惯了它。通常,在这里,你需要在操作前后进行一些重命名/重新排序。


我认为这也应该被称为“反透视表”...也许在0.13版本中会实现!:) - Andy Hayden

5

我提供另一种可能性,使用pd.stack函数:

df = pd.DataFrame(sample)
df = df.T.stack().reset_index()

详细解释

In [24]: df = pd.DataFrame(sample)

In [25]: df
Out[25]: 
       user1  user2  user3
item1    2.5    2.5    NaN
item2    3.5    3.0    4.5
item3    3.0    3.5    NaN
item4    3.5    4.0    NaN
item5    2.5    NaN    1.0
item6    3.0    NaN    4.0

应用 stack 会在已经使用 item 索引过的行轴子级上旋转列轴。由于你希望首先看到 user,让我们通过使用 .T 在转置的 DataFrame 上执行操作:

In [34]: df = df.T.stack()

In [35]: df
Out[35]: 
user1  item1    2.5
       item2    3.5
       item3    3.0
       item4    3.5
       item5    2.5
       item6    3.0
user2  item1    2.5
       item2    3.0
       item3    3.5
       item4    4.0
user3  item2    4.5
       item5    1.0
       item6    4.0
dtype: float64

您希望基本列而非索引,因此只需重置索引:

In [36]: df = df.reset_index()

In [37]: df
Out[37]: 
   level_0 level_1    0
0    user1   item1  2.5
1    user1   item2  3.5
2    user1   item3  3.0
3    user1   item4  3.5
4    user1   item5  2.5
5    user1   item6  3.0
6    user2   item1  2.5
7    user2   item2  3.0
8    user2   item3  3.5
9    user2   item4  4.0
10   user3   item2  4.5
11   user3   item5  1.0
12   user3   item6  4.0

2
这个与DSM提供的“melt”解决方案非常相似:
df = DataFrame(sample)
df = df.unstack().dropna().reset_index()
df = df.rename(columns={'level_0':'col1', 'level_1':'col2', 0:'col3'})

0

也许你可以尝试这样做。

temp=[]
for item in sample:
    temp.append(pandas.DataFrame(item))
self.results = pandas.concat(temp)

1
感谢您的快速回复。我尝试这个时,出现了以下错误: Traceback (most recent call last):   File "<stdin>", line 2, in <module>   File "pandas\core\frame.py", line 450, in init     raise PandasError('DataFrame constructor not properly called!') pandas.core.common.PandasError:未正确调用DataFrame构造函数! - Godel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接