У меня есть следующий фрейм данных (прочитанный из файла csv):
my_df:
my_date my_id values key factor
1/1/2024 _One 123 key1 .56
1/7/2024 _One 567 key1 .75
1/14/2024 _One 100 key1 .81
1/14/2024 _One 100 key2 .44
1/1/2024 _Two 150 key3 .91
1/7/2024 _Two 130 key3 .88
1/1/2024 _Three 200 key4 0
1/1/2024 _Three 200 key5 .45
Таким образом, существует совпадение определенных дат для двух или более ключей, принадлежащих одному и тому же идентификатору. Я хочу, чтобы мой фрейм данных выглядел следующим образом: мне нужно вычислить выделенные значения на основе весов факторов. Примечание: расчетный вес получается путем деления коэффициента на сумму коэффициентов в перекрывающихся периодах. Сказать,
my_df:
my_date my_id values key factor weights allocated_values
1/1/2024 _One 123 key1 0.56 1 123
1/7/2024 _One 500 key1 0.75 1 500
1/14/2024 _One 100 key1 0.81 0.648 64.8
1/14/2024 _One 100 key2 0.44 0.352 35.2
1/1/2024 _Two 160 key3 0.91 1 160
1/7/2024 _Two 130 key3 0.88 1 130
1/1/2024 _Three 200 key4 0 0.50 100
1/1/2024 _Three 200 key5 0.45 0.50 100
Чтобы достичь вышеуказанного результата, я выполняю следующую группу:
for name, group in my_df.groupby('my_id'):
for name1, group1 in group.groupby('key'):
factors = group1['factor']
weight = factors['factor']/factors.sum() if factors.sum() != 0 | (factors==0).any() else 1/len(factors)
#what i tried- approach1
group['weights'] = weight #doesn't work
#what i tried next
my_df['weights'] = my_df.update(group) #doesn't work
Я так устал, что не могу думать дальше. Поэтому разместите это здесь для любой помощи/руководства.
Был бы очень признателен за любые подсказки.






Вы можете попробовать использовать .groupby (вместо my_id и my_date) в сочетании с .transform, чтобы добиться этого:
df["allocated_values"] = (
df["values"] * df["factor"]
/ df.groupby(["my_id", "my_date"])["factor"].transform("sum")
)
Результат для образца:
my_date my_id values key factor allocated_values
0 1/1/2024 _One 123 key1 0.56 123.0
1 1/7/2024 _One 567 key1 0.75 567.0
2 1/14/2024 _One 100 key1 0.81 64.8
3 1/14/2024 _One 100 key2 0.44 35.2
4 1/1/2024 _Two 150 key3 0.91 150.0
5 1/7/2024 _Two 130 key3 0.88 130.0
Если вы хотите сохранить weights, попробуйте:
df = (
df.assign(weights=
df["factor"] / df.groupby(["my_id", "my_date"])["factor"].transform("sum"))
.assign(allocated_values=lambda df: df["values"] * df["weights"])
)
Результат для образца:
my_date my_id values key factor allocated_values weights
0 1/1/2024 _One 123 key1 0.56 123.0 1.000
1 1/7/2024 _One 567 key1 0.75 567.0 1.000
2 1/14/2024 _One 100 key1 0.81 64.8 0.648
3 1/14/2024 _One 100 key2 0.44 35.2 0.352
4 1/1/2024 _Two 150 key3 0.91 150.0 1.000
5 1/7/2024 _Two 130 key3 0.88 130.0 1.000
Что касается модификации: я не уверен, что полностью понимаю спецификацию, но вы можете попытаться изменить factor тех групп, которые содержат 0, установив для него значение 1, чтобы соответствующие веса были одинаковыми (1 / length of group):
df = (
df.assign(mask=df["factor"].ne(0))
.assign(mask=lambda df: df.groupby(["my_id", "my_date"])["mask"].transform("all"))
.assign(factor_alt=lambda df: df["factor"].where(df["mask"], 1))
.assign(weights=lambda df: df["factor_alt"]
/ df.groupby(["my_id", "my_date"])["factor_alt"].transform("sum"))
.assign(allocated_values=lambda df: df["values"] * df["weights"])
.drop(columns=["mask", "factor_alt"])
)
Первые два шага определяют группы, в которых встречается 0, а третий шаг соответствующим образом корректирует factor. Дальше то же самое, что и раньше, только с откорректированными factors.
Я получаю следующий результат с измененным вводом:
my_date my_id values key factor allocated_values weights
0 1/1/2024 _One 123 key1 0.56 123.0 1.000
1 1/7/2024 _One 567 key1 0.75 567.0 1.000
2 1/14/2024 _One 100 key1 0.81 64.8 0.648
3 1/14/2024 _One 100 key2 0.44 35.2 0.352
4 1/1/2024 _Two 150 key3 0.91 150.0 1.000
5 1/7/2024 _Two 130 key3 0.88 130.0 1.000
6 1/1/2024 _Three 200 key4 0.00 100.0 0.500
7 1/1/2024 _Three 200 key5 0.45 100.0 0.500
Возможно ли это? df["allocated_values"] = ( df["values"] * (df["фактор"] if df["фактор"].sum() != 0 | (df["фактор"]==0).any ()) else 1/len(df["фактор"]) / df.groupby(["my_id", "my_date"])["фактор"].transform("сумма") )
@ 5122014009 См. настройку: я не совсем уверен, что это выполняет требуемую работу, но вы можете попробовать.
Большое спасибо. Это работает, но есть одна небольшая проблема, с которой я все еще сталкиваюсь. Я обновил образец данных. @Тимус, не мог бы ты взглянуть?