#python #pandas
#python #pandas
Вопрос:
Я пытаюсь перебрать большое количество испытаний и вычислить средневзвешенное значение для нескольких подмножеств. В настоящее время данные представлены в формате long со столбцами trial, area score.
trial area score
0 T106 0 0.0035435
1 T106 1 0.0015967
2 T106 4 0.0003191
3 T106 4 0.1272919
4 T288 0 0.1272883
У меня около 120 000 испытаний, с 4 областями и, возможно, от 10 до 100 баллов за испытание, в общей сложности ~ 7 миллионов строк. Моей первой мыслью было перебрать все испытания в цикле по 4 областям, создать временный фрейм данных для вычисления результатов и добавления результатов во внешний фрейм данных:
for area in range(4):
for trial in trial_names.iloc[:,0]:
Tscore = 0
temp_trial = pd.DataFrame(trials_long.loc[(trials_long['tname'] == trial) amp; (trials_long['area'] == int(area))])
#match score in tria
temp_trial = temp_trial.merge(scores_df, how='left')
#sum score for all matching 'trial' 'area' #this will be weigted avrg, with >0.5 *2 and >0.9* 3
temp_trial.loc[temp_trial['score'] > 0.9, ['score']] *= 3 #weight 3x for >0.9
temp_trial.loc[temp_trial['score'] > 0.5, ['score']] *= 2 #weight 2x for >0.5
Tscore = temp_trial['score'].sum() / int(len(temp_trial.index))
trial_names.loc[trial,area] = Tscore #store Tscore somewhere
Tscore = 0
print('done')
Это решение занимает более 10 минут в одном потоке с частотой 4,0 ГГц. В этом случае время действительно имеет существенное значение, и вычисления должны выполняться менее чем за 15 секунд или около того. В R я обычно использую ряд векторизованных функций для пропуска циклов, и любые циклы, которые у меня были, будут распараллеливаться по нескольким ядрам, но в python я не знаком с лучшими подходами. Я также был бы открыт для изучения чего-то нового, возможно, хеш-карт?
Спасибо!
Комментарии:
1. на первый взгляд я чувствую, что вы можете просто использовать pandas
groupby
как для области, так и для пробной версии, затемapply
пользовательскую функцию для каждого подмножества, чтобы проверить ваши пороговые значения / рассчитать средневзвешенное значение. это сэкономит вам по крайней мере один из этих циклов for, но, вероятно, оба, если вы сможете векторизовать код внутри функции2. Возможно, поможет замена нескольких
df.loc
на udf за один запускdf.apply
с помощью.groupby
оба столбца — тоже хороший улов!
Ответ №1:
Это то, что я пробовал:
df['weighted'] = df['score']
df.loc[df['score']>.9, 'weighted'] *= 3
df.loc[df['score']>.5, 'weighted'] *= 2
# s is indexed by ('trial', 'area')
s = df.groupby(['trial', 'area']).weighted.mean()
потребовалось 1,16 секунды, чтобы обработать 7 миллионов строк на 6600 тыс.
Комментарии:
1. Это элегантное и эффективное решение. Спасибо!