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