如何按列中的列表元素索引数据?

时间:2016-12-21 17:06:33

标签: python python-3.x pandas group-by pandas-groupby

我有以下DataFrame(稍后命名为df2):

    recipe_id                                        ingredients
0        3332         [11307, 11322, 11632, 11338, 11478, 11438]
1        3333  [11322, 11338, 11632, 11314, 11682, 11478, 108...
2        3334  [11632, 11682, 11338, 11337, 10837, 11435, 113...
3        3335  [11149, 11322, 11532, 11996, 10616, 10837, 113...
4        3336  [11330, 11632, 11422, 11256, 11338, 11314, 114...
5        3812                      [959, 92, 3, 554, 12271, 202]
...

我想创建另一个具有以下列的DataFrame:['ingredients', "recipe_id1", "recipe_id2", ..., "recipe_idn"],其中n是数据库中的食谱总数。我用以下代码片段做到了这一点:

columns = ['ingredient'] + (list(df2['recipe_id'].unique()))
ingredient_df = pd.DataFrame(columns=columns)


在我创建了这个DataFrame(我已经做过)之后,填充它(问题我有),输出应该如下所示:

In [1]:
# Create and populate ingredient_df by some method
columns = ['ingredient'] + (list(df2['recipe_id'].unique()))
ingredient_df = pd.DataFrame(columns=columns)
ingredient_df = populate_df(ingredient_df, df2)
Out [1]:
In [2]:  
ingredient_df
Out[2]:
   ingredient  ... 3332 3333 3334 3335 3336 ...
...
   11322       ...    1    1    0    1    0 ...
...

在上面的示例中,(11322, 3334)的值为0,因为ID为3334的配方中不存在成分11322。

换句话说,如果配方中存在成分,我希望每种成分都有映射(ingredient, recipe_id) = 1,否则0。{/ p>

我设法通过迭代所有配方并通过所有成分来实现这一目标,但这非常缓慢。如何使用Pandas方法以更强大和更优雅的方式完成此操作(如果可行的话)?

1 个答案:

答案 0 :(得分:5)

设置

df = pd.DataFrame(
    dict(
        recipe_id=list('abcde'),
        ingredients=[list('xyz'),
                     list('tuv'),
                     list('ytw'),
                     list('vy'),
                     list('zxs')]
    )
)[['recipe_id', 'ingredients']]

df

  recipe_id ingredients
0         a   [x, y, z]
1         b   [t, u, v]
2         c   [y, t, w]
3         d      [v, y]
4         e   [z, x, s]

方法1

df.set_index('recipe_id').ingredients.apply(pd.value_counts) \
    .fillna(0).astype(int).T.rename_axis('ingredients')

recipe_id    a  b  c  d  e
ingredients               
s            0  0  0  0  1
t            0  1  1  0  0
u            0  1  0  0  0
v            0  1  0  1  0
w            0  0  1  0  0
x            1  0  0  0  1
y            1  0  1  1  0
z            1  0  0  0  1

方法2

idx = np.repeat(df.index.values, df.ingredients.str.len())
df1 = df.drop('ingredients', 1).loc[idx]
df1['ingredients'] = df.ingredients.sum()

df1.groupby('ingredients').recipe_id.apply(pd.value_counts) \
    .unstack(fill_value=0).rename_axis('recipe_id', 1)

recipe_id    a  b  c  d  e
ingredients               
s            0  0  0  0  1
t            0  1  1  0  0
u            0  1  0  0  0
v            0  1  0  1  0
w            0  0  1  0  0
x            1  0  0  0  1
y            1  0  1  1  0
z            1  0  0  0  1