我怎样才能建立一个更快的衰减平均值?将数据框的行日期字段与其他行日期进行比较

How can I build a faster decaying average? comparing a data frame's rows date field to other rows dates

我很笨拙,但 python 足够了。我经常引用堆栈,但这是我的第一个问题。我已经构建了一个衰减平均函数来作用于具有大约 10000 行的 pandas 数据框,但是 运行 需要 40 分钟。我将不胜感激有关如何加快速度的任何想法。这是实际数据的示例,经过了一些简化。

sub = pd.DataFrame({
        'user_id':[101,101,101,101,101,102,101],
        'class_section':['Modern Biology - B','Spanish Novice 1 - D', 'Modern Biology - B','Spanish Novice 1 - D','Spanish Novice 1 - D','Modern Biology - B','Spanish Novice 1 - D'],
        'sub_skill':['A','A','B','B','B','B','B'],
        'rating' :[2.0,3.0,3.0,2.0,3.0,2.0,2.0],
        'date' :['2019-10-16','2019-09-04','2019-09-04', '2019-09-04','2019-09-13','2019-10-16','2019-09-05']})

对于这个数据框:

sub
Out[716]: 
   user_id            class_section sub_skill  rating        date
0      101       Modern Biology - B         A     2.0  2019-10-16
1      101     Spanish Novice 1 - D         A     3.0  2019-09-04
2      101       Modern Biology - B         B     3.0  2019-09-04
3      101     Spanish Novice 1 - D         B     2.0  2019-09-04
4      101     Spanish Novice 1 - D         B     3.0  2019-09-13
5      102       Modern Biology - B         B     2.0  2019-10-16
6      101     Spanish Novice 1 - D         B     2.0  2019-09-05

衰减平均值对满足条件的最近事件进行全权加权,并对乘数小于 1 的每个先前事件进行加权。在这种情况下,乘数为 0.667。先前加权的事件再次加权。

因此,用户 101 的西班牙语评分 sub_skill B 的衰减平均值为:

(2.0*0.667^2 + 2.0*0.667^1 + 3.0*0.667^0)/((0.667^2 + 0.667^1 + 0.667^0) = 2.4735

这是我在阅读有用的文章后尝试的 post on weighted averages

sub['date'] = pd.to_datetime(sub.date_due) 

def func(date, user_id, class_section, sub_skill):
    return sub.apply(lambda row: row['date'] > date  
                     and row['user_id']==user_id 
                     and row['class_section']== class_section 
                     and row['sub_skill']==sub_skill,axis=1).sum()

# for some reason this next line of code took about 40 minutes to run on 9000 rows:
sub['decay_count']=sub.apply(lambda row: func(row['date'],row['user_id'], row['class_section'], row['sub_skill']), axis=1)

# calculate decay factor:
sub['decay_weight']=sub.apply(lambda row: 0.667**row['decay_count'], axis=1)

# calcuate decay average contributors (still needs to be summed):
g = sub.groupby(['user_id','class_section','sub_skill'])
sub['decay_avg'] = sub.decay_weight / g.decay_weight.transform("sum") * sub.rating

# new dataframe with indicator/course summaries as decaying average (note the sum):
indicator_summary = g.decay_avg.sum().to_frame(name = 'DAvg').reset_index()

我经常在 pandas 工作,我习惯于遍历大型数据集。我原以为这会花费行平方的时间,但它花费的时间要长得多。非常感谢一个更优雅的解决方案或一些加速它的建议!

这个项目的一些背景:我正在尝试自动将基于熟练程度的评分转换为我学校的经典课程评分。我有一个从我们的学习管理系统中提取数据到电子表格中的过程,该电子表格计算衰减的平均值,然后将信息发布给教师,但我想自动化整个过程并从中提取自己。 LMS 在实施基于熟练程度的系统方面进展缓慢,并且不愿意提供转换——这是有充分理由的。但是,我们必须将学生的熟练程度和我们向传统成绩的转换传达给家长和大学,因为这是他们所说的语言。

为什么不用groupby?这里的想法是按降序排列组内的日期并减去 1(因为排名从 1 开始)。这似乎反映了您在上面 func 中的逻辑,而不必尝试使用嵌套应用来调用应用。

sub['decay_count'] = sub.groupby(['user_id', 'class_section', 'sub_skill'])['date'].rank(method='first', ascending=False) - 1

sub['decay_weight'] = sub['decay_count'].apply(lambda x: 0.667 ** x)

输出:

sub.sort_values(['user_id', 'class_section', 'sub_skill', 'decay_count'])                                      

   user_id         class_section sub_skill  rating       date  decay_count  decay_weight
0      101    Modern Biology - B         A     2.0 2019-10-16          0.0      1.000000
2      101    Modern Biology - B         B     3.0 2019-09-04          0.0      1.000000
1      101  Spanish Novice 1 - D         A     3.0 2019-09-04          0.0      1.000000
3      101  Spanish Novice 1 - D         B     2.0 2019-09-04          0.0      1.000000
6      101  Spanish Novice 1 - D         B     2.0 2019-09-05          1.0      0.667000
4      101  Spanish Novice 1 - D         B     3.0 2019-09-13          2.0      0.444889
5      102    Modern Biology - B         B     2.0 2019-10-16          0.0      1.000000