熊猫,为每个用户获得第一,第二和第三名首选作者

时间:2019-05-06 14:31:20

标签: pandas dataframe pandas-groupby

我的熊猫数据框的格式为

 userID      author_cat  vote 
 234         1246        5.0
 121         2954        3.2
 234         1246        2.1
 121         2954        1.4
 234         1578        3.3
 234         1246        4.5
 121         2954        1.1
 121         9341        3.2

预期

 userID      author_cat  vote  first_author     second_author   third_author
 234         1246        5.0   1246             1578            0
 121         2954        3.2   2954             9341            0
 234         1246        2.1   1246             1578            0
 121         2954        1.4   2954             9341            0
 234         1578        3.3   1246             1578            0
 234         1246        4.5   1246             1578            0
 121         2954        1.1   2954             9341            0
 121         9341        3.2   2954             9341            0

我想为每个用户根据他们的评分来构造三列。出现次数最多的作者(同一作者撰写的更多书籍,并由一个用户复审)应出现在“ first_preferred_author”列中(类别,如1246)。第二和第三首选作者也是如此。如果作者不存在(第一,第二和第三,甚至所有三个作者都不存在,则三个新列应包含0)。

到目前为止,我已经根据用户的评论数量设法获得了作者的出现顺序,

df_new.groupby('userID')['author_cat'].value_counts()

但是我不知道从这里做什么。

编辑:

上面的命令返回一个pd.series.series(?),看起来像这样(在实际数据集上):

userID  author_cat
243     42994.0       6
        48986.0       5
        72473.0       3
        2505.0        2
        4371.0        2
        5270.0        2
        18764.0       2
        41267.0       2
        75183.0       2
        82066.0       2
        486.0         1
        571.0         1
        3507.0        1
        6343.0        1
        6524.0        1
        7530.0        1
        10539.0       1
        10679.0       1
        21123.0       1
        30948.0       1
        41305.0       1
        41479.0       1
        43715.0       1
        49236.0       1
        52183.0       1
        53204.0       1
        56812.0       1
        56916.0       1
        57911.0       1
        62266.0       1
                     ..
278633  54862.0       1
        57422.0       1
        66639.0       1
        72642.0       1
        72712.0       1
        73809.0       1
        82105.0       1
        87066.0       1
        91189.0       1
        93458.0       1
        94608.0       1
        96674.0       1
        99025.0       1
278843  80852.0       3
        3377.0        2
        4371.0        2
        2437.0        1
        2528.0        1
        5216.0        1
        18370.0       1
        30948.0       1
        35706.0       1
        37463.0       1
        40577.0       1
        62175.0       1
        62645.0       1
        81508.0       1
        92206.0       1
        92242.0       1
        93801.0       1
Name: author_cat, Length: 96302, dtype: int64

4 个答案:

答案 0 :(得分:3)

尝试一下:

(df.groupby(['userID']).author_cat
   .apply(lambda x: pd.Series(x.value_counts()
                               .nlargest(3).index))
   .unstack(level=1).fillna(0).astype(int))

示例(为多一位第三作者再添加一行121,2953,1.1

userID,author_cat,vote
234,1246,5.0
121,2954,3.2
234,1246,2.1
121,2954,1.4
234,1578,3.3
234,1246,4.5
121,2954,1.1
121,9341,3.2
121,2953,1.1

输出:

+--------+------+------+------+
|        |  0   |  1   |  2   |
+--------+------+------+------+
| UserID |      |      |      |
+--------+------+------+------+
| 121    | 2954 | 9341 | 2953 |
| 234    | 1246 | 1578 |    0 |
+--------+------+------+------+

答案 1 :(得分:0)

我不确定要为每列分配值。但是,您可以将nlargestgroupby结合使用,以获得每个用户的前三名作者:

df.groupby('userID').author_cat.value_counts().groupby('userID').nlargest(3)

userID  author_cat
121     2954          3
        9341          1
234     1246          3
        1578          1
Name: author_cat, dtype: int64

假设您的示例df与原始值计数相同,但是如果在完整数据集上运行它,则只会取回每个用户ID的前3个值计数。

答案 2 :(得分:0)

应该遵循以下步骤:

preferences = (
    df
    .groupby(['userID', 'author_cat'])
    .size()
    .rename('count')
    .pipe(lambda x: pd.DataFrame(x))
    .sort_values('count', ascending=False)
    .groupby('userID')
    .apply(lambda x: x.assign(rank=np.arange(len(x.index)) + 1)) # Adds incrementing rank even if counts are equal
    .reset_index()
    .set_index(['userID', 'rank'])
    ['author_cat']
    .unstack(1) # This "pivots" the dataframe
    .filter(lambda x: x <= 3, axis=1)
    .rename(columns={1: 'first_author', 2: 'second_author', 3: 'third_author'})
    .fillna(0)
    .astype('int')
)

df = df.join(preferences, on='userID')

相对于groupby().size(),我更喜欢value_counts(),它给出相似的结果,但保留索引级别的名称。

此外,请注意,如果同一author_cat的外观数量相同,则此实现不注意userID的顺序。

答案 3 :(得分:0)

不使用apply的解决方案。使用groupby.unique按出现顺序获得一系列唯一author_cat的列表。将其取消嵌套到数据框。将3列的值分别为0dfset_index上的dfuserID。最后,从update的数据帧中提取groupby.unique df:

d1 = df.groupby('userID')['author_cat'].unique()
d2 = pd.DataFrame(d1.tolist(), index=d1.index)

d2
Out[455]:
           0     1
userID
121     2954  9341
234     1246  1578

最后一步:

df[0], df[1], df[2] = 0, 0, 0
df.set_index('userID', inplace=True)
df.update(d2)

Out[456]:
        author_cat  vote       0       1  2
userID
234           1246   5.0  1246.0  1578.0  0
121           2954   3.2  2954.0  9341.0  0
234           1246   2.1  1246.0  1578.0  0
121           2954   1.4  2954.0  9341.0  0
234           1578   3.3  1246.0  1578.0  0
234           1246   4.5  1246.0  1578.0  0
121           2954   1.1  2954.0  9341.0  0
121           9341   3.2  2954.0  9341.0  0

您的样本没有第三列值,因此列2仍然位于0之后的update

如果您的数据具有第三列值,则输出将如下所示(注意:在这种情况下,我向您的示例中添加了一行以演示第三列):

Out[462]:
        author_cat    vote     0     1       2
userID
234           1246     5.0  1246  1578     0.0
121           2954     3.2  2954  9341  9954.0
234           1246     2.1  1246  1578     0.0
121           2954     1.4  2954  9341  9954.0
234           1578     3.3  1246  1578     0.0
234           1246     4.5  1246  1578     0.0
121           2954     1.1  2954  9341  9954.0
121           9341     3.2  2954  9341  9954.0
121           9954  9954.0  2954  9341  9954.0