Python 大熊猫不同水平的平均值

Python 大熊猫不同水平的平均值,python,pandas,Python,Pandas,我在MySQL数据库中有一个很大的音乐标签数据集,我正试图用pandas进行分析。我将其从MySQL导出到.tsv,现在将其作为数据帧读入以进行分析 数据中的每一行都是一个元组,指示给定用户(由数字用户ID表示)在特定时间使用特定标记(此处表示为数字ID)标记特定艺术家。因此,如果没有索引,数据样本将如下所示: uid artist tag date 0 2096963 559 46 2005-07-01 1 2096963 584

我在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','uid']).head()
我每月获得每个用户的注释数,即:

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

但是,有什么简单的方法可以得到用户每月的平均值呢?也就是说,每个月,“anno”列用户的平均值是多少?我有很多这样的指标要计算,所以我希望解决方案可以推广。

大型多索引可能会很麻烦。我建议放弃伪列“annotations”,使用
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()
要每天合计批注,请执行以下操作:

daily_users = data.groupby('date').uid.nunique()
daily_annotations = data.groupby('date').count()
每个用户的平均每日注释数就是每日注释总数除以当天的用户数。由于执行了
groupby
操作,这两个系列都按日期编制索引,因此它们将自动对齐

要平均每个用户每月的注释,最方便的方法是使用
重采样
,这是一个按不同时间频率分组的好功能

mean_monthly_annotations_per_user = mean_daily_anootations_per_user.resample('M')

我找到了一种适合我原来的多索引格式的替代方法,我认为比@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万行数据集,性能将是一个更大的问题):


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

我想从一开始就尝试使用重采样,但它似乎不起作用(至少不是您描述的那样)。以“日期”为索引,使用“平均值”重新采样仅计算艺术家、标签和用户每个月的所有数字ID的算术平均值(这是毫无意义的),而不是每个用户的注释平均数。”另一方面,Count'给出了每个月的行总数,这也是错误的。我需要每个用户每月的平均注释(行)数。我一直在编辑这个,因为我最初误解了你的问题。请再读一遍。我想我现在已经知道了。好得多,但唯一的问题是,每日注释的定义需要拉出一个特定的列,否则你不能进行划分(正如您所定义的,daily_annotations是一个数据帧,但daily_用户是一个系列。据我所知,您选择哪一列是任意的。编辑并接受答案。@DanAllan只需将一个函数传递给重采样,OP就可以做他想做的事情wants@Jeff你能举个例子吗?
%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