在熊猫中平均不同的水平

时间:2013-10-02 16:36:58

标签: python pandas

我在MySQL数据库中有一个大型音乐标记数据集,我试图用pandas进行分析。我将它从MySQL导出到.tsv,现在将其作为数据框读取进行分析。

数据中的每一行都是一个元组,表示给定用户(由数字用户ID表示)在特定时间用特定标记(此处表示为数字ID)标记特定艺术家。因此,如果没有索引,数据样本将如下所示:

       uid  artist   tag        date
0  2096963     559    46  2005-07-01
1  2096963     584  1053  2005-07-01
2  2096963     584  2044  2005-07-01
3  2096963     584  2713  2005-07-01
4  2096963     596   236  2005-07-01
...
       uid  artist   tag        date
99995  2656262    8095    57  2005-08-01
99996  2656262    8095    79  2005-08-01
99997  2656262    8095  4049  2005-08-01
99998  2656262    8095  8290  2005-08-01
99999  2610168    8095  1054  2005-08-01

为方便分析,我已将所有内容编入索引并添加了虚拟注释变量(数据中的每一行代表一个标记实例或注释)。所以现在我们有:

data = pd.read_table(filename,header=None, names=('uid','artist','tag','date'), index_col=['date','uid','artist','tag'], parse_dates='date') 
data['annotations'] = 1

In [41]: data.head()
Out[41]:
                                annotations
date       uid     artist tag
2005-07-01 2096963 559    46              1
                   584    1053            1
                          2044            1
                          2713            1
                   596    236             1
...

使用这样的格式化数据,计算简单的频率分布是微不足道的。例如,如果我想确定每个用户标记某些内容的次数(以降序频率顺序排列),那就简单如下:

data.sum(level='uid').sort('anno',ascending=False)

同样,我可以通过以下方式确定每个月(所有用户和标签)的注释总数:

data.sum(level='date')

但是我遇到了更复杂的计算问题。特别是,如果我想每个月每个用户的平均注释数量会怎么样?如果我打电话:

data.sum(level=['date','uid']).head()

我每个月都得到每个用户的注释数量,即:

                    anno
date       uid
2005-07-01 1040740    10
           1067454    23
           2096963   136
           2115894     1
           2163842     4
...

但是,然后通过简单的方法获得跨用户的月平均值?也就是说,对于每个月,“anno”列的用户平均值是多少?我有各种各样的指标,我想计算,所以我希望解决方案能够概括。

2 个答案:

答案 0 :(得分:2)

Big MultiIndexes可能很麻烦。我建议放弃您的虚拟列,“注释”,并使用count代替sum

首先,读入数据而不指定索引,即

pd.read_table(filename,header=None, names=['uid','artist','tag','date'], parse_dates='date')

计算每个用户的注释:

data.groupby('uid').count().sort(ascending=False)

每天总注释:

data.groupby('date').count()

每天统计唯一身份用户:

daily_users = data.groupby('date').uid.nunique()

每天总注释:

daily_annotations = data.groupby('date').count()

每个用户的平均每日注释只是每日总注释除以当天的用户数。 作为groupby操作的结果,这两个系列都按日期编制索引,因此它们将自动对齐。

mean_daily_annotations_per_user = daily_annotations/daily_users

要在每个用户之间平均注释,最方便的是使用resample,这是一个很好的功能,可以按不同的时间频率进行分组。

mean_monthly_annotations_per_user = mean_daily_anootations_per_user.resample('M')

答案 1 :(得分:1)

我找到了一种适合我原来的多索引格式的替代方法,而且认为比@DanAllan提出的方法更快。

回想一下,我们计算每个用户每月的平均注释,让我们构建两个数据帧(我这里只使用了一部分数据,因此是nrows参数)。 data1是带有虚拟变量的多索引版本,data2是@DanAllan提出的无索引版本

indexes=['date','uid','artist','iid','tag']
data1 = pd.read_table(filename,header=None, nrows=1000000, names=('uid','iid','artist','tag','date'),index_col=indexes, parse_dates='date') 
data['anno']=1
data2 = pd.read_table(filename,header=None, nrows=1000000, names=('uid','iid','artist','tag','date'), parse_dates='date') 

使用未索引的(data2)版本,该过程为:

daily_users = data2.groupby('date').uid.nunique()
daily_annotations = data2.groupby('date').count().uid
anno_per_user_perday2 = daily_annotations / daily_users.map(float)

使用多索引版本(data1),我们可以:

anno_per_user_perday = data1.sum(level=['date','uid']).mean(level='date').anno

结果完全相同,但索引版本的速度快了两倍(对于完整的5000万行数据集,性能将更加严重):

%timeit -n100 daily_users = data2.groupby('date').uid.nunique() ; daily_annotations = data2.groupby('date').count().uid ; anno_per_user_perday2 = daily_annotations / daily_users.map(float)
100 loops, best of 3: 387 ms per loop

%timeit -n100 anno_per_user_perday1 = data1.sum(level=['date','uid']).mean(level='date').anno
100 loops, best of 3: 149 ms per loop

使用索引版本生成数据帧的速度较慢,但​​它提供的灵活性似乎值得。