将函数应用于pandas groupby和indexing

时间:2017-08-29 14:28:57

标签: python pandas dataframe pandas-groupby

我想了解熊猫群岛,但我现在看到一些我不明白的行为。基本上,我有一个看起来像的数据集(只显示头部):

 userId movieId rating  timestamp   parsed_time
0   1   2       3.5     1112486027  2005-04-02 23:53:47
1   1   29      3.5     1112484676  2005-04-02 23:31:16
2   1   32      3.5     1112484819  2005-04-02 23:33:39
3   1   47      3.5     1112484727  2005-04-02 23:32:07
4   1   50      3.5     1112484580  2005-04-02 23:29:40

我已经检查了数据集的NaN / null值,但没有。现在,我想计算每部电影的平均评分,以及标准偏差。

获得平均评分很简单:

ratings = pd.read_csv('ratings.csv', sep=',')

average_rating = ratings[['movieId','rating']].groupby('movieId',as_index=False).mean()
average_ratings.rename(columns={'rating':'AverageRating'}, inplace=True)

这给了我类似的东西:

 movieId    AverageRating
0   1     3.921240
1   2     3.211977
2   3     3.151040
3   4     2.861393
4   5     3.064592

所以这一切都很好,以及我对groupby()mean()组合的期望。 现在,我想做同样的事情来计算电影评级的标准偏差,并将其作为新列添加到average_rating df:

average_rating['StdDev'] = ratings[['movieId','rating']].groupby('movieId').std()

给了我:

    movieId AverageRating   StdDev
0   1       3.921240    NaN
1   2       3.211977    0.889012
2   3       3.151040    0.951150
3   4       2.861393    1.006642
4   5       3.064592    1.095702

这里让我感到困惑的是,NaN在我的StdDev专栏中首次出现。如果我手动提取行,比如movieId [1,2]并计算平均值和标准偏差,那就是:

print('Mean movieID 1:')
print(ratings[ratings['movieId']==1]['rating'].mean())
print('StdDev movieID 1:')
print(ratings[ratings['movieId']==1]['rating'].std())
print('Mean movieID:')
print(ratings[ratings['movieId']==2]['rating'].mean())
print('StdDev movieID 2:')
print(ratings[ratings['movieId']==2]['rating'].std())

我回来了:

Mean movieID 1:
3.921240
StdDev movieID 1:
0.889012
Mean movieID 2:
3.211977
StdDev movieID 2:
0.951150

所以对我来说,看起来groupby.std()由于某种原因跳过第一个索引,用NaN替换它,然后填入正确的值,但移动了一个索引。我不明白这种行为,这不是我所期望的。任何人都可以在第二次使用groupby时向我解释这种行为,以及如何避免它/让它做我想做的事情?

2 个答案:

答案 0 :(得分:2)

问题不是在计算标准差时发生,而是在将结果分配给新列StdDev时发生。这是因为pandas隐式地通过索引进行分配。

以下代码应该有效,因为groupby操作的结果都在movieId上编入索引:

# note how I remove as_index=False
average_rating = ratings[['movieId','rating']].groupby('movieId').mean()
average_rating['StdDev'] = ratings[['movieId','rating']].groupby('movieId').std()

当然,你应该一气呵成:

ratings[['movieId','rating']].groupby('movieId').agg(['mean', 'std'])

更优雅(或至少更标准):

ratings.groupby('movieId')['rating'].agg(['mean', 'std'])

答案 1 :(得分:2)

这里的关键是,在你的第一个groupby中,你包括as_index=False,所以创建的df有一个新的串行索引。在您的secong groupby中,您不包含as_index参数,因此它使用MovieID作为索引。

当您在average_ratings中将其指定为列时,索引不是指同一个事物。

在这种情况下恰好发生看起来您的索引已被移位,因为您有MovieID 1-5,整数索引0-4。 StdDev列中的空值仅反映了没有ID = 0的电影的事实。