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}}

我正在寻找将其转换为结构如下的熊猫数据框

     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

任何想法将不胜感激:)

4

5 回答 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()
])
于 2013-08-10T12:45:26.573 回答
13

我认为你所追求的操作——取消透视表——被称为“熔化”。在这种情况下,困难的部分可以通过 来完成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一旦你习惯了它就非常有用。通常,就像这里一样,您在前后进行一些重命名/重新排序。

于 2013-08-10T13:06:03.240 回答
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命令对转置的 DataFrame 进行操作.T

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
于 2013-08-10T13:39:57.863 回答
2

melt这个与DSM 提供的解决方案非常相似:

df = DataFrame(sample)
df = df.unstack().dropna().reset_index()
df = df.rename(columns={'level_0':'col1', 'level_1':'col2', 0:'col3'})
于 2013-08-10T13:35:55.707 回答
0

也许你可以尝试这样做。

temp=[]
for item in sample:
    temp.append(pandas.DataFrame(item))
self.results = pandas.concat(temp)
于 2013-08-10T12:38:48.380 回答