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

2024-10-06 12:03:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我笨手笨脚,但能熟练地使用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_技能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在实施基于熟练程度的系统方面进展缓慢,并且不愿意提供转换——这是有充分理由的。然而,我们必须向家长和大学传达学生熟练程度和我们向传统年级的转换,因为这是他们所说的语言


Tags: to数据iddatesectionskillclassrow
1条回答
网友
1楼 · 发布于 2024-10-06 12:03:34

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

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

相关问题 更多 >