【问题标题】:Numpy "where" with multiple conditions具有多个条件的 Numpy“位置”
【发布时间】:2016-12-30 17:55:37
【问题描述】:

我尝试在数据帧“df_energy”中添加一个新列“energy_class”,如果“consumption_energy”值 > 400,它包含字符串“high”,如果“consumption_energy”值介于 200 和 400 之间,则为“medium” ,如果“consumption_energy”值低于 200,则为“low”。 我尝试使用 numpy 中的 np.where,但我看到 numpy.where(condition[, x, y]) 只处理两个条件,而不是像我的情况那样处理 3。

有什么好办法帮帮我吗?

提前谢谢你

【问题讨论】:

  • 为什么不使用numpy.select()

标签: python pandas numpy dataframe


【解决方案1】:

试试这个: 使用来自@Maxu 的设置

col         = 'consumption_energy'
conditions  = [ df2[col] >= 400, (df2[col] < 400) & (df2[col]> 200), df2[col] <= 200 ]
choices     = [ "high", 'medium', 'low' ]
    
df2["energy_class"] = np.select(conditions, choices, default=np.nan)


  consumption_energy energy_class
0                 459         high
1                 416         high
2                 186          low
3                 250       medium
4                 411         high
5                 210       medium
6                 343       medium
7                 328       medium
8                 208       medium
9                 223       medium

【讨论】:

  • 这太棒了。请注意,这与大多数if / elif / else 函数一样工作,如果满足第一个第二个条件,则第一个将适用,而不是第二个。谢谢@Merlin
  • 我正在尝试使用此设置,但在我的情况下,我正在检查列是否包含某些字符串值并且这不起作用并且我收到错误(ValueError:系列的真值是模糊的。)。任何想法为什么?这是我的问题:stackoverflow.com/questions/64806956/…
  • 最佳答案!
【解决方案2】:

您可以使用ternary

np.where(consumption_energy > 400, 'high', 
         (np.where(consumption_energy < 200, 'low', 'medium')))

【讨论】:

  • 我认为这很好,除非你有复杂的多重条件,那么这可能是一个大问题。
  • 同意。对于更复杂的事情,我会使用@Maxu 的pd.cut 解决方案。
【解决方案3】:

我喜欢保持代码干净。这就是为什么我更喜欢np.vectorize 来处理此类任务。

def conditions(x):
    if x > 400:
        return "High"
    elif x > 200:
        return "Medium"
    else:
        return "Low"

func = np.vectorize(conditions)
energy_class = func(df_energy["consumption_energy"])

然后只需使用以下命令将 numpy 数组作为列添加到数据框中:

df_energy["energy_class"] = energy_class

这种方法的优点是,如果您希望向列添加更复杂的约束,则可以轻松完成。 希望对您有所帮助。

【讨论】:

    【解决方案4】:

    我会在这里使用cut() 方法,它会生成非常高效且节省内存的category dtype:

    In [124]: df
    Out[124]:
       consumption_energy
    0                 459
    1                 416
    2                 186
    3                 250
    4                 411
    5                 210
    6                 343
    7                 328
    8                 208
    9                 223
    
    In [125]: pd.cut(df.consumption_energy,
                     [0, 200, 400, np.inf],
                     labels=['low','medium','high']
              )
    Out[125]:
    0      high
    1      high
    2       low
    3    medium
    4      high
    5    medium
    6    medium
    7    medium
    8    medium
    9    medium
    Name: consumption_energy, dtype: category
    Categories (3, object): [low < medium < high]
    

    【讨论】:

    • 嘿max,在这个方法中是200包含在中还是低?
    • @Datanovice,它应该属于“中等”类别,因为默认情况下包含间隔的所有右边缘
    • @Datanovice,实际上我错了 - 它应该属于“低”类别,因为它是第一个区间的右边缘
    【解决方案5】:

    警告:小心使用 NaN

    请务必小心,如果您的数据有缺失值,np.where 可能难以使用,并且可能会无意中给您错误的结果。

    考虑这种情况:

    df['cons_ener_cat'] = np.where(df.consumption_energy > 400, 'high', 
             (np.where(df.consumption_energy < 200, 'low', 'medium')))
    
    # if we do not use this second line, then
    #  if consumption energy is missing it would be shown medium, which is WRONG.
    df.loc[df.consumption_energy.isnull(), 'cons_ener_cat'] = np.nan
    

    或者,您可以使用一个嵌套的np.where 用于中等而不是难看的 nan。

    恕我直言,最好的方法是pd.cut。它处理 NaN 并且易于使用。

    示例:

    import numpy as np
    import pandas as pd
    import seaborn as sns
    
    df = sns.load_dataset('titanic')
    
    # pd.cut
    df['age_cat'] = pd.cut(df.age, [0, 20, 60, np.inf], labels=['child','medium','old'])
    
    
    # manually add another line for nans
    df['age_cat2'] = np.where(df.age > 60, 'old', (np.where(df.age <20, 'child', 'medium')))
    df.loc[df.age.isnull(), 'age_cat'] = np.nan
    
    # multiple nested where
    df['age_cat3'] = np.where(df.age > 60, 'old',
                             (np.where(df.age <20, 'child',
                                       np.where(df.age.isnull(), np.nan, 'medium'))))
    
    # outptus
    print(df[['age','age_cat','age_cat2','age_cat3']].head(7))
        age age_cat age_cat2 age_cat3
    0  22.0  medium   medium   medium
    1  38.0  medium   medium   medium
    2  26.0  medium   medium   medium
    3  35.0  medium   medium   medium
    4  35.0  medium   medium   medium
    5   NaN     NaN   medium      nan
    6  54.0  medium   medium   medium
    

    【讨论】:

      【解决方案6】:

      我第二次使用 np.vectorize。它比 np.where 快得多,而且代码更简洁。您绝对可以通过更大的数据集来判断速度。您可以为条件句以及这些条件的输出使用字典格式。

      # Vectorizing with numpy 
      row_dic = {'Condition1':'high',
                'Condition2':'medium',
                'Condition3':'low',
                'Condition4':'lowest'}
      
      def Conditions(dfSeries_element,dictionary):
          '''
          dfSeries_element is an element from df_series 
          dictionary: is the dictionary of your conditions with their outcome
          '''
          if dfSeries_element in dictionary.keys():
              return dictionary[dfSeries]
      
      def VectorizeConditions():
          func = np.vectorize(Conditions)
          result_vector = func(df['Series'],row_dic)
          df['new_Series'] = result_vector
      
          # running the below function will apply multi conditional formatting to your df
      VectorizeConditions()
      

      【讨论】:

        【解决方案7】:
        myassign["assign3"]=np.where(myassign["points"]>90,"genius",(np.where((myassign["points"]>50) & (myassign["points"]<90),"good","bad"))
        

        当您只想使用“where”方法但有多个条件时。我们可以通过与上面相同的方法添加更多(np.where)来添加更多条件。最后两个将是您想要的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-16
          • 2019-07-21
          • 1970-01-01
          • 2011-08-25
          • 2016-08-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多