Сравните два столбца с помощью панд

104

Используя это как отправную точку:

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

Out[8]: 
  one  two three
0   10  1.2   4.2
1   15  70   0.03
2    8   5     0

Я хочу использовать что-то вроде ifоператора в пандах.

if df['one'] >= df['two'] and df['one'] <= df['three']:
    df['que'] = df['one']

По сути, проверяйте каждую строку с помощью ifоператора, создавайте новый столбец.

Документы говорят, что нужно использовать, .allно нет примера ...

Мерлин
источник
Каким должно быть значение, если ifутверждение есть False?
Alex Riley
3
@Merlin: Если у вас есть числовые данные в столбце, лучше не смешивать их со строками. Это изменит тип столбца на object. Это позволяет хранить в столбце произвольные объекты Python, но это происходит за счет более медленных числовых вычислений. Таким образом, если столбец хранит числовые данные, предпочтительнее использовать NaN для не-чисел.
unutbu
1
Имея целых чисел в виде строк и пытается сделать сравнение на них выглядит странно: a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]. Это создает запутанные результаты с «правильным» кодом: df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])] дает результат 10для первой строки, тогда как он должен давать результат, NaNесли входные данные были целыми числами.
Primer

Ответы:

147

Вы можете использовать np.where . Если cond- логический массив, Aа B- массивы, то

C = np.where(cond, A, B)

определяет, что C равно Aгде condTrue, а Bгде condFalse.

import numpy as np
import pandas as pd

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

df['que'] = np.where((df['one'] >= df['two']) & (df['one'] <= df['three'])
                     , df['one'], np.nan)

дает

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03  NaN
2   8    5     0  NaN

Если у вас более одного условия, вы можете вместо этого использовать np.select . Например, если вы хотите df['que']равняться, df['two']когда df['one'] < df['two'], то

conditions = [
    (df['one'] >= df['two']) & (df['one'] <= df['three']), 
    df['one'] < df['two']]

choices = [df['one'], df['two']]

df['que'] = np.select(conditions, choices, default=np.nan)

дает

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03   70
2   8    5     0  NaN

Если мы можем предположить, что df['one'] >= df['two']when df['one'] < df['two']имеет значение False, тогда условия и варианты можно упростить до

conditions = [
    df['one'] < df['two'],
    df['one'] <= df['three']]

choices = [df['two'], df['one']]

(Предположение может быть неверным, если df['one']или df['two']содержат NaN.)


Обратите внимание, что

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

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

df2 = df.astype(float)

Однако это меняет результаты, поскольку строки сравниваются посимвольно, а числа с плавающей запятой сравниваются численно.

In [61]: '10' <= '4.2'
Out[61]: True

In [62]: 10 <= 4.2
Out[62]: False
Unutbu
источник
73

Вы можете использовать .equalsдля столбцов или целых фреймов данных.

df['col1'].equals(df['col2'])

Если они равны, этот оператор вернется True, иначе False.

ccook5760
источник
22
Примечание: при этом сравнивается только весь столбец с другим. Это не сравнение столбцов по элементам
guerda
1
Как насчет того, чтобы видеть, всегда ли один столбец имеет значение «больше» или «меньше» других столбцов?
rrlamichhane
28

Вы можете использовать apply () и сделать что-то вроде этого

df['que'] = df.apply(lambda x : x['one'] if x['one'] >= x['two'] and x['one'] <= x['three'] else "", axis=1)

или если вы предпочитаете не использовать лямбда

def que(x):
    if x['one'] >= x['two'] and x['one'] <= x['three']:
        return x['one']
    return ''
df['que'] = df.apply(que, axis=1)
Боб Хаффнер
источник
2
Я подозреваю, что это, вероятно, немного медленнее, чем другие опубликованные подходы, поскольку он не использует преимущества векторизованных операций, которые позволяет pandas.
Мариус
@BobHaffner: лямбда-выражения не читаются при использовании сложных операторов if / then / else.
Мерлин
@Merlin, вы можете добавить elseif, и я согласен с вами по лямбдам и множественным условиям
Боб Хаффнер,
есть ли способ обобщить функцию, отличную от лямбда, так, чтобы вы могли передавать столбцы фрейма данных и не изменять имя?
AZhao 09
@AZhao вы можете обобщить с iloc следующим образом: df ['que'] = df.apply (lambda x: x.iloc [0] if x.iloc [0]> = x.iloc [1] and x.iloc [0] ] <= x.iloc [2] else "", axis = 1) Вы это имеете в виду? Очевидно. порядок ваших столбцов имеет значение
Боб Хаффнер
9

Один из способов - использовать логический ряд для индексации столбца df['one']. Это дает вам новый столбец, в котором Trueзаписи имеют то же значение, что и та же строка, что df['one']и Falseзначения NaN.

Логический ряд просто задается вашим ifутверждением (хотя его необходимо использовать &вместо and):

>>> df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])]
>>> df
    one two three   que
0   10  1.2 4.2      10
1   15  70  0.03    NaN
2   8   5   0       NaN

Если вы хотите, чтобы NaNзначения были заменены другими значениями, вы можете использовать этот fillnaметод в новом столбце que. Я использовал здесь 0вместо пустой строки:

>>> df['que'] = df['que'].fillna(0)
>>> df
    one two three   que
0   10  1.2   4.2    10
1   15   70  0.03     0
2    8    5     0     0
Алекс Райли
источник
4

Заключите каждое отдельное условие в круглые скобки, а затем используйте &оператор для объединения условий:

df.loc[(df['one'] >= df['two']) & (df['one'] <= df['three']), 'que'] = df['one']

Вы можете заполнить несоответствующие строки, просто используя ~(оператор "not"), чтобы инвертировать совпадение:

df.loc[~ ((df['one'] >= df['two']) & (df['one'] <= df['three'])), 'que'] = ''

Вы должны использовать &и ~вместо того , andи notпотому , что &и ~операторы работают элемент-на-элемент.

Конечный результат:

df
Out[8]: 
  one  two three que
0  10  1.2   4.2  10
1  15   70  0.03    
2   8    5     0  
Мариус
источник
1

Используйте, np.selectесли у вас есть несколько условий, которые нужно проверить из фрейма данных и вывести конкретный вариант в другом столбце

conditions=[(condition1),(condition2)]
choices=["choice1","chocie2"]

df["new column"]=np.select=(condtion,choice,default=)

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

psn1997
источник
0

Я думаю, что наиболее близким к интуиции OP является встроенный оператор if:

df['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) 
Ник Скоццаро
источник
Ваш код выдает ошибкуdf['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) ^ SyntaxError: unexpected EOF while parsing
vasili111