【问题标题】:Compare two columns using pandas使用 pandas 比较两列
【发布时间】:2015-02-13 00:15:05
【问题描述】:

以此为起点:

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

我想在 pandas 中使用类似 if 的语句。

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

基本上,通过if 语句检查每一行,创建新列。

文档说要使用.all,但没有示例...

【问题讨论】:

  • 如果if语句是False,值应该是多少?
  • @Merlin:如果列中有数字数据,最好不要与字符串混合。这样做会将列的 dtype 更改为 object。这允许将任意 Python 对象存储在列中,但其代价是数值计算速度较慢。因此,如果该列存储数字数据,则最好将 NaN 用于非数字。
  • 将整数作为字符串并尝试对它们进行比较看起来很奇怪:a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]。这会使用“正确”代码产生令人困惑的结果:df['que'] = df['one'][(df['one'] &gt;= df['two']) &amp; (df['one'] &lt;= df['three'])] 在第一行产生10,而如果输入是整数,它应该产生NaN

标签: python pandas if-statement dataframe


【解决方案1】:

您可以使用np.where。如果cond是一个布尔数组,而AB是数组,那么

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

定义 C 等于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'] &lt; 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'] &gt;= df['two']df['one'] &lt; 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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 注意:这只会将整列与另一列进行比较。这不会明智地比较列元素
    • 如果您想查看一列是否始终具有“大于”或“小于”其他列的值?
    【解决方案3】:

    你可以使用 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)
    

    【讨论】:

    • 我怀疑这可能比发布的其他方法慢一些,因为它没有利用 pandas 允许的矢量化操作。
    • @BobHaffner: lambda 在使用复杂的 if/then/else 语句时不可读。
    • @Merlin 你可以添加一个 elseif,我会同意你的 lambdas 和多个条件
    • 有没有一种方法可以概括非 lambda 函数,以便您可以传入数据框列而不更改名称?
    • @AZhao 你可以像这样用 iloc 概括 df['que'] = df.apply(lambda x : x.iloc[0] if x.iloc[0] >= x.iloc[ 1] 和 x.iloc[0]
    【解决方案4】:

    一种方法是使用布尔系列来索引列df['one']。这会为您提供一个新列,其中 True 条目与 df['one'] 的同一行具有相同的值,而 False 的值是 NaN

    布尔系列只是由您的if 语句给出(尽管有必要使用&amp; 而不是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 值替换为其他值,可以在新列que 上使用fillna 方法。我在这里使用了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
    

    【讨论】:

      【解决方案5】:

      将每个单独的条件括在括号中,然后使用&amp; 运算符组合条件:

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

      您需要使用&amp;~ 而不是andnot,因为&amp;~ 运算符可以逐个元素地工作。

      最终结果:

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

      【讨论】:

        【解决方案6】:

        如果您要从数据框中检查多个条件并在不同的列中输出特定选择,请使用 np.select

        conditions=[(condition1),(condition2)]
        choices=["choice1","chocie2"]
        
        df["new column"]=np.select=(condtion,choice,default=)
        

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

        【讨论】:

          【解决方案7】:

          我想为那些试图比较具有NaN 值的两列中值的相等性并在两个值均为NaN 时得到False 的人添加此答案。根据定义,NaN != NaN(参见:numpy.isnan(value) not the same as value == numpy.nan?)。

          如果你想让两个NaN比较返回True,你可以使用:

          df['compare'] = (df["col_1"] == df["col_2"]) | (df["col_1"].isna() & df["col_2"].isna())
          

          【讨论】:

            【解决方案8】:

            使用 lambda 表达式:

            df[df.apply(lambda x: x['col1'] != x['col2'], axis = 1)]
            

            【讨论】:

              【解决方案9】:

              可以使用Series方法where

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

              结果:

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

              【讨论】:

                【解决方案10】:

                我认为最接近 OP 直觉的是内联 if 语句:

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

                【讨论】:

                • 你的代码给了我错误df['que'] = (df['one'] if ((df['one'] &gt;= df['two']) and (df['one'] &lt;= df['three'])) ^ SyntaxError: unexpected EOF while parsing
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-01-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多