Цикл for с условными операторами не работает должным образом (Pandas)

#Loop through example dataset 
for id in df['val_id']:
        #total assigned value 
        df['tot_val'] = 0
        #loop through facilities 
        for fac in df['fac_id']:
            if df['product'].isin(['XL', 'CL', 'DL']).all():
                df['row'] = min(df['our_val_amt'] - df['tot_val'], df['val_against'])
            else:
                df['row'] = 0
                
            df['tot_val'] = df['tot_val'] + df['row']
            df['row'] = df['row'] + 1


Sample to test val_against > val_amt change
# df = pd.DataFrame(data=[["compx","xx1","yy1",424,418,"XL"],["compx","xx1","yy2",424,134,"CL"],["compx","xx2","yy3",472,60,"DL"],["compx","xx2","yy4",472,104,"CL"], ["compx", "xx3", "yy5", 490, 50, "XL"], ["compx", "xx3", "yy6", 490, 500, "CL"], ["compx", "xx3", "yy7", 490, 200, "DL"], ["compx", "xx4", "yy8", 510, 200, "CL"], ["compx", "xx4", "yy9", 510, 300, "CL"], ["compx", "xx4", "yy10", 510, 50, "XL"]], columns=["name","val_id","fac_id","our_val_amt","val_against","product"])


Я пытаюсь в Pandas выполнить двойной цикл через столбцы «val_id» и «fac_id» и создать новое поле из следующих условий.

1. В каждом цикле 'val_id', если 'product' == 'CL', то минимум из 'val_against' и 'our_val_amt', например. min( val_against (134), our_val_amt (424)) поэтому 'NEW FIELD' = 134. Также, если сумма NEW FIELD превышает "our_val_amt", вычтите ее из "our_val_amt". например для val_id "xx4", (200 + 300 + 50) = 550, что превышает our_val_amt=510, поэтому NEW FILED = 550 - 510 = 10.

2. Если продукт != 'CL' и находится в той же группе 'val_id'. Остаток, который нужно вычесть из «our_val_amt», будет вставлен в «NEW FIELD». например, 'our_val_amt' (424) - из шага 1 (134) = 290. Это вставлено над 'NEW FIELD'.

3.Повторите шаги для val_id xx2. Расчет NEW FIELD для CL = 104 и XL = 472 - 104 = 368.

Набор данных с вычисляемыми полями, помеченными **

|  name | val_id | fac_id  | our_val_amt | val_against | product | **row** | **totval**|**Field Want**
| compx |  xx1   |  yy1    |   424       |    418      |   XL    |   290   |     0     |   290
| compx |  xx1   |  yy2    |   424       |    134      |   CL    |   134   |    134    |   134
| compx |  xx2   |  yy3    |   472       |    60       |   DL    |   0     |     0     |   368
| compx |  xx2   |  yy4    |   472       |    104      |   CL    |   104   |   104     |   104
| compx |  xx3   |  yy5    |   490       |    50       |   XL    | 
| compx |  xx3   |  yy6    |   490       |    500      |   CL    | 
| compx |  xx3   |  yy7    |   490       |    200      |   DL    | 
| compx |  xx4   |  yy8    |   510       |    200      |   CL    | 
| compx |  xx4   |  yy9    |   510       |    300      |   CL    | 
| compx |  xx4   |  yy10   |   510       |    50       |   CL    | 

Ожидаемый результат

|  name | val_id | fac_id  | our_val_amt | val_against | product | new field |
| compx |  xx1   |  yy1    |   424       |    418      |   XL    | 290       | 
| compx |  xx1   |  yy2    |   424       |    134      |   CL    |  134      |  
| compx |  xx2   |  yy3    |   472       |    60       |   DL    | 368       |  
| compx |  xx2   |  yy4    |   472       |    104      |   CL    |  104      |
| compx |  xx3   |  yy5    |   490       |    50       |   XL    | 0         | 
| compx |  xx3   |  yy6    |   490       |    500      |   CL    |  490      |  
| compx |  xx3   |  yy7    |   490       |    200      |   DL    | 0         |  
| compx |  xx4   |  yy8    |   510       |    200      |   CL    |  200      |
| compx |  xx4   |  yy9    |   510       |    300      |   CL    |  300      |
| compx |  xx4   |  yy10   |   510       |    50       |   CL    |  10       |

**row** и **totval** — это поля, которые я создал, пытаясь создать поле, которое мне нужно, с помощью приведенной выше логики.

Я попытался сгруппировать переменные вместе и иметь «продукт» в виде столбцов, но, к сожалению, я получаю более 6000 столбцов и понятия не имею, как вычислить расчет для этого сценария.

Я также пытался выполнить цикл, но получил неверные результаты/ошибки

error: Истинное значение Серии неоднозначно. Используйте a.empty, a.bool(), a.item(), a.any() или a.all()

Всегда ли у вас есть пара записей CL и non-CL для заданного val_id? Другими словами, как вы обрабатываете несколько записей CL или несколько записей, не относящихся к CL, для расчета остатка?

Azhar Khan 17.01.2023 09:37

Что, если 'val_against' >= 'our_val_amt'?

Azhar Khan 17.01.2023 10:01

Привет, Ажар, это правильно, всегда есть пара CL и не CL для данного val_id. Если существует несколько CL для одного val_id, он сначала передается им, а затем распределяется среди не-CL. Другой пример: Val_id xx1 имеет val amt 442, но на этот раз содержит три продукта (XL – 418, CL – 134, CL – 100). Этот сценарий будет распространяться следующим образом: CL - 100, CL - 134 и остаток 190 до XL. Если val_against > our_val_amt, мы берем все 'our_val_amt'. например, val_id xx1 'our_val_amt' = 100 и val_against = 150 для CL и 100 для XL. Берем 100 против CL и оставляем XL с 0.

svenvuko 17.01.2023 12:24

Привет, Ажар, задаю вопрос, если у вас есть время посмотреть. stackoverflow.com/questions/75216508/… Заранее спасибо

svenvuko 01.02.2023 03:49
Почему в 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
4
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы можете решить это в 2 шага:

  • На шаге 1 вычислите новые значения поля для «CL». Следующее решение предполагает значение 0 для new_field, если условие вычисления не выполняется.
  • На шаге 2 обработайте записи, отличные от CL, и используйте значения, вычисленные на шаге 1. Чтобы обработать случай, когда несколько записей «CL» могут присутствовать в одной и той же группе val_id, следующий код суммирует их.

Комментарии добавляются перед каждым шагом, чтобы объяснить, что он делает.

df = pd.DataFrame(data=[["compx","xx1","yy1",424,418,"XL"],["compx","xx1","yy2",424,134,"CL"],["compx","xx2","yy3",472,60,"DL"],["compx","xx2","yy4",472,104,"CL"],
                        ["compx","xx3","yy5",490,50,"XL"],["compx","xx3","yy6",490,500,"CL"],["compx","xx3","yy7",490,200,"DL"],
                        ["compx","xx4","yy8",510,200,"CL"],["compx","xx4","yy9",510,300,"CL"],["compx","xx4","yy10",510,50,"CL"],
                        ], columns=["name","val_id","fac_id","our_val_amt","val_against","product"])

# Compute tuple of "our_val_amt", "val_against" and "product" for easy processing as one column. It is hard to process multiple columns with "transform()".
df["the_tuple"] = df[["our_val_amt", "val_against", "product"]].apply(tuple, axis=1)

def compute_new_field_for_cl(g):
  # df_g is a tuple ("our_val_amt", "val_against", "product") indexed as (0, 1, 2).
  df_g = g.apply(pd.Series)
  df_g["new_field"] = df_g.apply(lambda row: min(row[0], row[1]) if row[2] == "CL" else 0, axis=1)
  df_g["cumsum"] = df_g["new_field"].cumsum()
  df_g["new_field"] = df_g.apply(lambda row: 0 if row["cumsum"] > row[0] else row["new_field"], axis=1)
  df_g["max_cumsum"] = df_g["new_field"].cumsum()
  df_g["new_field"] = df_g.apply(lambda row: row[0] - row["max_cumsum"] if row["cumsum"] > row[0] else row["new_field"], axis=1)
  return df_g["new_field"]

# Apply above function and compute new field values for "CL".
df["new_field"] = df.groupby("val_id")[["the_tuple"]].transform(compute_new_field_for_cl)

# Re-compute tuple of "our_val_amt", "new_field" and "product".
df["the_tuple"] = df[["our_val_amt", "new_field", "product"]].apply(tuple, axis=1)

def compute_new_field_for_not_cl(g):
  # df_g is a tuple ("our_val_amt", "new_field", "product") indexed as (0, 1, 2).
  df_g = g.apply(pd.Series)
  result_sr = df_g.where(df_g[2] != "CL")[0] - df_g[df_g[2] == "CL"][1].sum()
  result_sr = result_sr.fillna(0) + df_g[1]
  return result_sr

# Apply above function and compute new field values for "CL".
df["new_field"] = df.groupby("val_id")[["the_tuple"]].transform(compute_new_field_for_not_cl)

df = df.drop("the_tuple", axis=1)

print(df)

Выход:

    name val_id fac_id  our_val_amt  val_against product  new_field
0  compx    xx1    yy1          424          418      XL      290.0
1  compx    xx1    yy2          424          134      CL      134.0
2  compx    xx2    yy3          472           60      DL      368.0
3  compx    xx2    yy4          472          104      CL      104.0
4  compx    xx3    yy5          490           50      XL        0.0
5  compx    xx3    yy6          490          500      CL      490.0
6  compx    xx3    yy7          490          200      DL        0.0
7  compx    xx4    yy8          510          200      CL      200.0
8  compx    xx4    yy9          510          300      CL      300.0
9  compx    xx4   yy10          510           50      CL       10.0

Привет Ажар, Спасибо за вашу помощь с программой. К сожалению, при запуске скрипта мой new_field выводит 708, 134, 428 и 104 (без изменений в скрипте). Кроме того, знаете ли вы, как я могу добавить условие в оператор where для сценариев, где our_val_amt > val_against? Я попытался создать новый result_sr, но, похоже, перезаписал существующий и сделал & | операторы без особого успеха.

svenvuko 18.01.2023 00:12

Похоже, второй результат_sr = result_sr.fillna(o) + df_g[1] вызывает 708 и 428

svenvuko 18.01.2023 00:14

Я вижу новые значения полей в соответствии с вашим ожидаемым результатом. Можете ли вы добавить неудачный пример и ожидаемый результат?

Azhar Khan 18.01.2023 01:44

Также добавьте примеры данных и ожидаемые результаты для нескольких случаев использования CL и других вариантов использования.

Azhar Khan 18.01.2023 01:47

Извинения, я теперь разрешил неожиданный вывод. Я только спрашиваю теперь, как обслуживать val_against >= our_val_amt в созданном коде. result_sr = df_g.where((df_g[2] == "CL") & (df_g[1] < df_g[0]))[1] Как включить в оператор - df_g.where((df_g[2] = = "CL") & (df_g[1] > df_g[0]))[0] Спасибо!!

svenvuko 18.01.2023 06:40

Пожалуйста, добавьте образец для условия val_against >= our_val_amt, чтобы я мог протестировать изменения.

Azhar Khan 18.01.2023 06:58

Пожалуйста, найдите пример, прикрепленный к кадру данных. Я добавил два сценария с одним val_against >= our_val_amt, а также несколькими CL для тестирования. Еще раз спасибо

svenvuko 18.01.2023 07:25

Почему новое поле 10 в последней записи? Или это опечатка? Думаю, так и должно быть 50.

Azhar Khan 18.01.2023 07:41

Нет 10 правильно. Это потому, что наш val amt = 510 и у нас заканчивается. 300 + 200 + 10 = 510.

svenvuko 18.01.2023 07:44

Я не понимаю вашей логики для последней строки. Это противоречит остальной логике для "CL". Вы должны обновить вопрос с правильной логикой.

Azhar Khan 18.01.2023 07:48

Привет, Ажар, если есть возможность ответить на продолжение этого вопроса stackoverflow.com/questions/75216508/…

svenvuko 24.01.2023 01:54

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