2013-10-02 102 views
2

我有一个庞大的音乐标记数据在MySQL数据库中的数据集,我试图用大熊猫进行分析。我将它从MySQL导出到.tsv文件,然后将其作为数据框读入以供分析。平均在熊猫的不同级别

数据中的每一行都是一个元组,指示特定用户(由数字用户标识表示)在特定时间用特定标签(在此表示为数字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”列的用户平均数是多少?我有我想要计算的各种指标,所以我希望解决方案能够推广。

回答

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) 

随着多索引版本(数据1),我们可以这样做:

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

结果是完全一样的,但快两倍多与索引的版本(性能会更成问题的充分,50英里llion行数据集):

%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 

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

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') 
+0

我想从一开始就尝试重新采样,但它似乎不起作用(至少不是你如何描述)。以'date'作为索引,重新采样'mean'只是计算艺术家,标签和用户每个月的所有数字ID的算术平均值(这是没有意义的),而不是每个用户的平均注释数量。另一方面,'计数'给出了每个月的总行数,这也是错误的。我需要每个用户每个月的平均注释数(行)。 – moustachio

+0

我一直在编辑这个,因为我最初误解了你的问题。请再读一遍。我想我现在已经明白了。 –

+0

好得多,但唯一的问题是daily_annotations的定义需要抽出一个特定的列,否则你不能进行分割(如你所定义的那样,daily_annotations是一个数据框,但daily_users是一个系列。任意选择哪一列,据我所知,编辑并接受答案 – moustachio