Создание нового столбца на основе условия if-elif-else

У меня есть DataFrame df:

    A    B
a   2    2 
b   3    1
c   1    3

Я хочу создать новый столбец на основе следующих критериев:

если строка A == B: 0

если rowA > B: 1

если строка A < B: -1

поэтому, учитывая приведенную выше таблицу, это должно быть:

    A    B    C
a   2    2    0
b   3    1    1
c   1    3   -1 

Для типичных if else случаев я использую np.where(df.A > df.B, 1, -1), предоставляет ли pandas специальный синтаксис для решения моей проблемы за один шаг (без необходимости создавать 3 новых столбца и затем объединять результат)?


person nutship    schedule 11.02.2014    source источник
comment
Вы можете просто определить функцию и передать это apply и установить axis=1, чтобы работать, не уверен, что я могу придумать операцию, которая дала бы вам то, что вы хотите   -  person EdChum    schedule 11.02.2014
comment
Ваше решение подразумевает создание 3 столбцов и объединение их в 1 столбец, или вы имеете в виду что-то другое?   -  person nutship    schedule 11.02.2014
comment
Вы все время говорите о создании трех столбцов, но я не совсем понимаю, о чем вы.   -  person DSM    schedule 11.02.2014
comment
@DSM ответил на этот вопрос, но я имел в виду что-то вроде df['C']=df.apply(myFunc(row), axis=1), где myFunc делает то, что вы хотите, это не связано с созданием «3 столбцов».   -  person EdChum    schedule 11.02.2014
comment
Возможный дубликат Pandas условного создания столбца серии / фрейма данных   -  person Georgy    schedule 02.05.2018


Ответы (5)


Чтобы формализовать некоторые из изложенных выше подходов:

Создайте функцию, которая работает со строками вашего фрейма данных следующим образом:

def f(row):
    if row['A'] == row['B']:
        val = 0
    elif row['A'] > row['B']:
        val = 1
    else:
        val = -1
    return val

Затем примените его к фрейму данных, передавая параметр axis=1:

In [1]: df['C'] = df.apply(f, axis=1)

In [2]: df
Out[2]:
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1

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

Изменить

Вот векторизованная версия

df['C'] = np.where(
    df['A'] == df['B'], 0, np.where(
    df['A'] >  df['B'], 1, -1)) 
person Zelazny7    schedule 11.02.2014
comment
Что, если я хочу передать другой параметр вместе со строкой в ​​функции? Если я это сделаю, он говорит, что строка не определена. - person prashanth manohar; 22.03.2017
comment
Вы должны использовать параметр args функции .apply: pandas.pydata.org/pandas-docs/stable/generated/ - person Zelazny7; 22.03.2017
comment
Я старый пользователь SAS, изучающий Python, и мне определенно нужно научиться! :-) Например, приведенный выше код можно было бы записать на SAS как: data df; set df; if A=B then C=0; else if A>B then C=1; else C=-1; run; Очень элегантно и просто. - person RobertF; 22.02.2019
comment
Спасибо за ответ. Однако я не мог понять, зачем нужен axis=1. Без прохождения axis=1 в строке был только 1-й столбец. - person h3xh4wk; 26.04.2019
comment
@ Zelazny7 не могли бы вы дать векторизованную версию? - person Averell; 11.11.2020

df.loc[df['A'] == df['B'], 'C'] = 0
df.loc[df['A'] > df['B'], 'C'] = 1
df.loc[df['A'] < df['B'], 'C'] = -1

Легко решить с помощью индексации. Первая строка кода выглядит так: если столбец A равен столбцу B, тогда создайте и установите столбец C равным 0.

person Brian    schedule 17.10.2016

Для этой конкретной связи вы можете использовать np.sign:

>>> df["C"] = np.sign(df.A - df.B)
>>> df
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1
person DSM    schedule 11.02.2014

введите описание изображения здесь

Допустим, выше один - это ваш исходный фрейм данных, и вы хотите добавить новый столбец `` старый ''

Если возраст старше 50 лет, мы считаем, что старше = да, в противном случае - неверно

шаг 1: получить индексы строк, возраст которых превышает 50

row_indexes=df[df['age']>=50].index

шаг 2: Используя .loc, мы можем присвоить новое значение столбцу

df.loc[row_indexes,'elderly']="yes"

то же самое для детей младше 50 лет

row_indexes=df[df['age']<50].index

df[row_indexes,'elderly']="no"

person Ravi    schedule 12.09.2018

Если у вас несколько if условий, numpy.select - это способ идти:

In [4102]: import numpy as np
In [4098]: conditions = [df.A.eq(df.B), df.A.gt(df.B), df.A.lt(df.B)]
In [4096]: choices = [0, 1, -1]

In [4100]: df['C'] = np.select(conditions, choices)

In [4101]: df
Out[4101]: 
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1
person Mayank Porwal    schedule 30.11.2020