2014-12-14 3 views
26

Используя это в качестве отправной точки:Сравнение двух столбцов с помощью панд

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, но нет ни одного примера ...

+0

Каким должно быть значение, если выражение 'if' является' False'? –

+0

Ох, давайте скажем "" ... thnks. – Merlin

+2

@Merlin: Если у вас числовые данные в столбце, лучше не смешивать его со строками. Это изменяет dtype столбца на 'object'. Это позволяет хранить произвольные объекты Python в столбце, но это связано с более медленными численными вычислениями. Таким образом, если столбец хранит числовые данные, предпочтительным является использование NaN для не-чисел. – unutbu

ответ

31

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

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

определяет С равным A где cond правда, и B где cond ложна.

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']] 

(Th е предположение не может быть истинным, если 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 
17

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

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'] 
    else: 
     '' 
df['que'] = df.apply(que, axis=1) 
+2

Я подозреваю, что это, вероятно, немного медленнее, чем другие опубликованные подходы, поскольку он не использует преимущества векторизованных операций, разрешенных пандами. – Marius

+2

Может быть.Мне нравится читаемость, хотя –

+1

Не мог бы добавить ответ, где def используется вместо lambda, спасибо – Merlin

4

Wrap каждое отдельное условие в скобках, а затем использовать оператор & совместить условия:

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, потому что Операторы & и ~ работают поэтапно.

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

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

Один из способов заключается в использовании булеву серии для индексации столбца 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

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

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

Если они равны, то оператор будет возвращать True, иначе False.

Смежные вопросы