使用熊猫比较两列


103

以此为起点:

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 2014年

3
@Merlin:如果一列中有数字数据,则最好不要将其与字符串混合。这样做会将列的dtype更改为object。这样可以将任意Python对象存储在该列中,但这样做的代价是数值计算速度较慢。因此,如果该列存储数字数据,则最好将NaN用于非数字。
unutbu 2014年

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 2014年

Answers:


146

您可以使用np.where。如果cond是布尔数组,A并且B是数组,则

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

将C定义为等于A哪里cond为True,B哪里cond为False。

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

72

您可以将其.equals用于列或整个数据框。

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

如果它们相等,则该语句将返回Trueelse False


22
注意:这只会将整列与另一列进行比较。这不能与智慧地比较列元素
guerda '18

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)

或者如果您不想使用lambda

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
我怀疑这可能比发布的其他方法慢一些,因为它没有利用熊猫允许的矢量化操作。
Marius 2014年

@BobHaffner:使用复杂的if / then / else语句时,无法读取lambda。
Merlin

@Merlin,您可以添加elseif,在lambda和多种条件下,我会同意您的意见
Bob Haffner 2014年

有没有一种方法可以泛化非lambda函数,以便您可以传入数据框列,而不更改名称?
2015年

@AZhao您可以像这样使用iloc进行概括:df ['que'] = df.apply(lambda x:x.iloc [0]如果x.iloc [0]> = x.iloc [1]和x.iloc [0 ] <= x.iloc [2]否则“”,axis = 1)那是您的意思吗?明显。列的顺序很重要
Bob Haffner

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

注意:没有条件,没有选择项应该匹配,如果对于两个不同的条件您有相同的选择,请重复选择文本


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.