Как группировать и присваивать значения серий каждой строке?

У меня есть следующий фрейм данных (прочитанный из файла 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
              

Я так устал, что не могу думать дальше. Поэтому разместите это здесь для любой помощи/руководства.

Был бы очень признателен за любые подсказки.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете попробовать использовать .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

Большое спасибо. Это работает, но есть одна небольшая проблема, с которой я все еще сталкиваюсь. Я обновил образец данных. @Тимус, не мог бы ты взглянуть?

5122014009 24.06.2024 12:02

Возможно ли это? 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 24.06.2024 12:21

@ 5122014009 См. настройку: я не совсем уверен, что это выполняет требуемую работу, но вы можете попробовать.

Timus 24.06.2024 13:23

Другие вопросы по теме