Как сделать цикл for с несколькими условиями if - PullRequest
1 голос
/ 23 мая 2019

У меня есть df (форма (5928, 22)), и я пытаюсь создать новый столбец и добавить значения на основе нескольких условий.

Условия будут:

    if CH == 20 then value = 268,34
    if CH == 24 then value = 322,02
    if CH == 30 then value = 492,65
    if CH == 40 then value = 536,69

    and

    if CH == 20 & ID in (5105561300, 5105561301, 5105561302, 5105561304) then value = 417,43
    if CH == 24 & ID in (5105561300, 5105561301, 5105561302, 5105561304) then value = 500,91
    if CH == 30 & ID in (5105561300, 5105561301, 5105561302, 5105561304) then value = 626,34
    if CH == 40 & ID in (5105561300, 5105561301, 5105561302, 5105561304) then value = 834,85

Когда я пытаюсь добавить новый столбец и добавлять значения, основанные на первом блоке условий, он работает отлично.

new_value = []

for row in df['CH']:
    if row == 20:
        new_value.append(268.34)
    elif row == 24:
        new_value.append(322.02)
    elif row == 30:
        new_value.append(402.65)
    elif row == 40:
        new_value.append(536.69)
    else:
        new_value.append(0)

df['new_value'] = new_value

Когда я пытался добавить другие условия, это не сработало. Код будет что-то вроде:

new_value = []

for row in df['CH']:
    if row == 20 and df['ID'] not in (5105561300, 5105561301, 5105561302, 5105561304):
         new_value.append(268.34)
    elif row == 20 and df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(417.43)
    elif row == 24 and df['ID'] not in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(268.34)
    elif row == 24 and df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(500.91)
    elif row == 30 and df['ID'] not in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(268.34)
    elif row == 30 and df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(626.34)
    elif row == 40 and df['ID'] not in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(268.34)
    elif row == 40 and df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(834.85)
    else:
        new_value.append(0)

    df['new_value'] = new_value

Когда я пробую код выше, я получаю следующее сообщение об ошибке:

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

Я не знаю, как идти отсюда. В SQL я бы использовал два простых оператора WHERE, но я не могу заставить его работать в Python.

Ответы [ 3 ]

1 голос
/ 23 мая 2019

Вариант № 1: два map, один isin и np.where

mtrue  = {20: 268.34, 24: 322.02, 30: 492.65, 40: 536.69}
mfalse = {20: 417.43, 24: 500.91, 30: 626.34, 40: 834.85}
ids = {5105561300, 5105561301, 5105561302, 5105561304}

df['new_value'] = np.where(df['ID'].isin(ids), df['CH'].map(mtrue), df['CH'].map(mfalse))

Вариант № 2: Один map и zip

mtrue  = {20: 268.34, 24: 322.02, 30: 492.65, 40: 536.69}
mfalse = {20: 417.43, 24: 500.91, 30: 626.34, 40: 834.85}
ids = {5105561300, 5105561301, 5105561302, 5105561304}
m = {
    (b, k): v for b, d in zip([True, False], [mtrue, mfalse])
    for k, v in d.items()
}

df['new_value'] = [*map(m.get, zip(df['ID'].isin(ids), df['CH']))]

Эквивалентно:

На всякий случай вы можете сделать [*map...]

df['new_value'] = [m[t] for t in zip(df['ID'].isin(ids), df['CH']))]
1 голос
/ 23 мая 2019

Проблема вашего кода в df['ID']. Измените цикл по строкам следующим образом, чтобы исправить сообщение об ошибке:

for row, id in zip(df['CH'], df['ID']):
    if row == 20 and id not in (5105561300, 5105561301, 5105561302, 5105561304):
        new_value.append(268.34)
    elif row == 20 and id in (5105561300, 5105561301, 5105561302, 5105561304):
        ...

Поскольку ваш набор данных не очень большой, вы можете использоватьпонимание списка для решения этой задачи:

# a set of ids to check existence
wlist = { 5105561300, 5105561301, 5105561302, 5105561304 }

# the value of each key is a list with the first element using the value 
# when id not in wlist and the 2nd element the value when id is in wlist
mapping = {
    20: [268.34, 417.43]
  , 24: [322.02, 500.91]
  , 30: [492.65, 626.34]
  , 40: [536.69, 834.85]
}

# new_value will depend on if CH is in mapping and id in wlist
df['new_value'] = [ mapping[ch][int(id in wlist)] if ch in mapping else 0 for ch, id in zip(df.CH, df.ID) ]
0 голосов
/ 23 мая 2019

Похоже, вы могли бы немного объединить это и избежать избыточности:

default = 268.34

for row in df['CH']:
    id_check = df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304)
    if row == 20:
        new_value = 417.43
    elif row == 24:
        new_value = 500.91
    elif row == 30:
        new_value = 626.34
    elif row == 40
        new_value = 834.85
    else:
        new_value = 0
    df['new_value'] = default if not id_check else value

Или вы можете отобразить это:

def get_new_value(row):
    d = { 20: 417.43,
             24: 500.91,
             30: 626.34,
             40: 834.85 }
    return d.get(row, 0)

default = 268.34
for row in df['CH']:
    id_check = df['ID'] in (5105561300, 5105561301, 5105561302, 5105561304)
    new_value = default if not id_check else get_new_value(row)

    df['new_value'] = new_value
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...