Порівняйте два стовпці за допомогою панд


105

Використовуючи це як вихідну точку:

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: Якщо в стовпці є числові дані, найкраще не змішувати їх із рядками. Це змінює тип d стовпця на 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якщо введенням були цілі числа.
Буквар

Відповіді:


148

Ви можете використовувати 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']коли df['one'] < df['two']False, тоді умови та вибір можна спростити

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

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

(Припущення може не відповідати дійсності, якщо містить NaN df['one']або df['two']містить його.)


Зауважте, що

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

73

Ви можете використовувати .equalsдля стовпців або цілих кадрів даних.

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

Якщо вони рівні, це твердження повернеться True, інакше False.


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
Я підозрюю, що це, можливо, трохи повільніше, ніж інші опубліковані підходи, оскільки він не використовує переваги векторизованих операцій, які дозволяють панди.
Маріус

@BobHaffner: лямбда-зчитування не читаються при використанні складних операторів if / then / else.
Мерлін

@Merlin, ти можеш додати інший файл, і я б погодився з тобою щодо лямбда та кількох умов
Боб Хаффнер

чи є спосіб узагальнити не лямбда-функцію таким чином, щоб ви могли передавати стовпці фрейму даних, а не змінювати ім'я?
AZhao

@AZhao ви можете узагальнити за допомогою iloc, наприклад, df ['que'] = df.apply (лямбда x: x.iloc [0], якщо x.iloc [0]> = x.iloc [1] та x.iloc [0 ] <= x.iloc [2] else "", ось = 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']

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

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

Вам потрібно використовувати &і, ~а не andі notтому, що оператори &and ~працюють поелементно.

Кінцевий результат:

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=)

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


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.