2

我在 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”列的用户的平均值是多少?我有各种像这样的指标要计算,所以我希望解决方案能够推广。

4

2 回答 2

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')
于 2013-10-02T17:10:53.560 回答
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

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

于 2013-10-02T19:49:03.573 回答