У меня есть фрейм данных pandas, который выглядит так
import pandas as pd
data = {
"Race_ID": [2,2,2,2,2,5,5,5,5,5,5],
"Student_ID": [1,2,3,4,5,9,10,2,3,6,5],
"theta": [8,9,2,12,4,5,30,3,2,1,50]
}
df = pd.DataFrame(data)
И я хотел бы создать новый столбец df['feature']
следующим методом: для каждого Race_ID
предположим, что Student_ID
равен i, тогда мы определяем функцию как
def f(thetak, thetaj, thetai, *theta):
prod = 1;
for t in theta:
prod = prod * t;
return ((thetai + thetaj) / (thetai + thetaj + thetai * thetak)) * prod
где k,j,l — это Student_ID
внутри одного и того же Race_ID
, такие что k =/= i, j=/=i,k, l=/=k,j,i и theta_i — это theta
, где Student_ID
равно i. Например, для Race_ID
=2, Student_ID
=1 у нас есть функция, равная
f(2,3,1,4,5)+f(2,3,1,5,4)+f(2,4,1,3,5)+f(2,4,1,5,3 )+f(2,5,1,3,4)+f(2,5,1,4,3)+f(3,2,1,4,5)+f(3,2,1,5 ,4)+f(3,4,1,2,5)+f(3,4,1,5,2)+f(3,5,1,2,4)+f(3,5,1 ,4,2)+f(4,2,1,3,5)+f(4,2,1,5,3)+f(4,3,1,2,5)+f(4,3 ,1,5,2)+f(4,5,1,2,3)+f(4,5,1,3,2)+f(5,2,1,3,4)+f(5 ,2,1,4,3)+f(5,3,1,2,4)+f(5,3,1,4,2)+f(5,4,1,2,3)+f (5,4,1,3,2)
что равно 299,1960138012742.
Но, как быстро понимаешь, количество членов в сумме растет суперэкспоненциально с увеличением количества студентов в забеге: если в забеге n учеников, то их (n-1)! условия в сумме.
К счастью, благодаря свойству симметрии f мы можем сократить количество членов до простых (n-1)(n-2), отметив следующее:
Пусть заданы i,j,k и 1,2,3 (например, ради) отличаются от i,j,k (т.е. 1,2,3 находятся в *arg). Тогда f(k,j,i,1,2,3) = f(k,j,i,1,3,2) = f(k,j,i,2,1,3) = f(k, j,i,2,3,1) = f(k,j,i,3,1,2) = f(k,j,i,3,2,1). Следовательно, мы можем уменьшить количество членов, если просто вычислим любой из членов, а затем умножим его на (n-3)!
Так, например, для Race_ID
=5, Student_ID
=9 нужно было бы суммировать 5!=120 членов, но, используя указанное выше свойство симметрии, нам нужно суммировать только 5x4 = 20 членов (5 вариантов для k, 4 варианта для i и 1 (неединственный выбор) для l), а именно
f(2,3,9,5,6,10)+f(2,5,9,3,6,10)+f(2,6,9,3,5,10)+f(2,10 ,9,3,5,6)+f(3,2,9,5,6,10)+f(3,5,9,3,6,10)+f(3,6,9,2, 5,10)+f(3,10,9,2,5,6)+f(5,2,9,3,6,10)+f(5,3,9,2,6,10)+ f(5,6,9,2,3,10)+f(5,10,9,2,3,6)+f(6,2,9,3,5,10)+f(6,3 ,9,2,5,10)+f(6,5,9,2,3,10)+f(6,10,9,2,3,5)+f(10,2,9,3, 5,6)+f(10,3,9,2,5,6)+f(10,5,9,2,3,6)+f(10,6,9,2,3,5)
и показатель для ученика 9 в забеге 5 будет равен указанной выше сумме, умноженной на 3! = 53588,197759
Итак, вопрос: как мне записать сумму для приведенного выше кадра данных? Я вычислил функции вручную для проверки, и желаемый результат выглядит так:
import pandas as pd
data = {
"Race_ID": [2,2,2,2,2,5,5,5,5,5,5],
"Student_ID": [1,2,3,4,5,9,10,2,3,6,5],
"theta": [8,9,2,12,4,5,30,3,2,1,50],
"feature": [299.1960138012742, 268.93506341257876, 634.7909309816431, 204.18901708653254, 483.7234700875771, 53588.197759, 9395.539167178009, 78005.26224935807, 92907.8753942894, 118315.38359654899, 5600.243276203378]
}
df = pd.DataFrame(data)
Большое спасибо.
@EmmanuelMurairi Да, чтобы мы могли сэкономить вычисления и вычислить меньше терминов
@ScottBoston Да, для RaceID = 2 длина *theta равна 2, а для RaceID = 5 длина *theta равна 3. В общем, для расы с n учениками длина *theta равна n-3. .
Этот код можно настроить и сделать быстрее:
import pandas as pd
import numpy as np
from itertools import permutations
data = {
"Race_ID": [2,2,2,2,2,5,5,5,5,5,5],
"Student_ID": [1,2,3,4,5,9,10,2,3,6,5],
"theta": [8,9,2,12,4,5,30,3,2,1,50]
}
df = pd.DataFrame(data)
Определить функции:
def f(thetak, thetaj, thetai, *theta):
prod = 1;
for t in theta:
prod *= t;
return ((thetai + thetaj) / (thetai + thetaj + thetai * thetak)) * prod
def student_race_theta(si, thetas, student):
total = 0
for ts in permutations(range(1, len(si)+1)):
if si.iloc[ts[2]-1] == student:
thetak, thetaj, thetai, *theta = [thetas.iloc[i-1] for i in ts]
total += f(thetak, thetaj, thetai, *theta)
return total
def fxs(x):
s = pd.Series()
for i, r in x.iterrows():
s[i] = student_race_theta(x['Student_ID'], x['theta'], r['Student_ID'])
return s
df['feature'] = df.groupby('Race_ID', group_keys=False)\
[['Race_ID', 'Student_ID', 'theta']].apply(fxs)
print(df)
Выход:
Race_ID Student_ID theta feature
0 2 1 8 299.196014
1 2 2 9 268.935063
2 2 3 2 634.790931
3 2 4 12 204.189017
4 2 5 4 483.723470
5 5 9 5 53588.197759
6 5 10 30 9395.539167
7 5 2 3 78005.262249
8 5 3 2 92907.875394
9 5 6 1 118315.383597
10 5 5 50 5600.243276
Я не совпадаю с вашей строкой Race_ID 5, Student_iD 9, но все остальные значения совпадают.
Только что проверил свои расчеты, вы были правы, я обновил число. Огромное спасибо, вы гений!
Спасибо. Никакого гения, просто какое-то время работал с Python и пандами. Я уверен, что это можно сделать лучше. Приятного кодирования!
Вы спрашиваете, как написать функцию Python, которая вычисляет второе математическое выражение для вашей функции f?