Я неуклюж, но адекватен с python. Я часто ссылаюсь на стек, но это мой первый вопрос. Я построил функцию усредняющего затухания, которая воздействует на фрейм данных pandas с примерно 10000 строками, но для запуска требуется 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
Затухающее среднее взвешивает самое последнее событие, которое соответствует условиям в полном весе и взвешивает каждое предыдущее событие с множителем меньше единицы. В этом случае множитель составляет 0,667. ранее взвешенные события снова взвешиваются.
Таким образом, среднее значение затухания для рейтинга пользователя 101 в Spani sh 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
Вот что я попробовал, прочитав полезный пост о средневзвешенных значениях
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, и я привык к итерации больших наборов данных. Я ожидал бы, что это займет время в квадрате строк, но это займет гораздо больше времени. Более элегантное решение или несколько советов очень хотелось бы ускорить его!
Некоторые сведения об этом проекте: я пытаюсь автоматизировать переход от оценки на основе квалификации к классу c для моей школы. У меня есть процесс извлечение данных из нашей системы управления обучением в электронную таблицу, которая вычисляет среднее значение затухания, а затем отправляет информацию учителям, но я хотел бы автоматизировать весь процесс и извлечь себя из него. LMS не спешит внедрять систему, основанную на умениях, и неохотно обеспечивает преобразование - по уважительной причине. Тем не менее, мы должны сообщить родителям и колледжам как уровень знаний учащихся, так и их переход в традиционный класс, поскольку на этом языке они говорят.