使用各个自定义容器(阈值)对 Pandas 列进行分类

Categorizing Pandas column with the indiviual custom bins (tresholds)

我有一个 dataframe,其中一些数值存储在 "value" 列中,并附有它们各自的分类阈值(在本例中为警告级别),存储在其他列中(在我的例子中 "low""middle""high" ):

     value    low  middle    high
0   179.69  17.42   88.87  239.85
1     2.58  17.81   93.37  236.58
2     1.21   0.05    0.01    0.91
3     1.66   0.20    0.32    4.57
4     3.54   0.04    0.04    0.71
5     5.97   0.16    0.17    2.55
6     5.39   0.86    1.62    9.01
7     1.20   0.03    0.01    0.31
8     3.19   0.08    0.01    0.45
9     0.02   0.03    0.01    0.10
10    3.98   0.18    0.05    0.83
11  134.51  78.63  136.86  478.27
12  254.53  83.73  146.33  486.65
13   15.36  86.07   13.74  185.16
14   85.10  86.12   13.74  185.16
15   15.12   1.37    6.09   30.12

我想知道每个值属于哪个类别(例如,第一个值是 middle,第二个是 below_low,因为它比它的任何阈值都小,第三个是 high,......你明白了)。所以这是预期的输出:

     value    low  middle    high   category
0   179.69  17.42   88.87  239.85     middle
1     2.58  17.81   93.37  236.58  below_low
2     1.21   0.05    0.01    0.91       high
3     1.66   0.20    0.32    4.57     middle
4     3.54   0.04    0.04    0.71       high
5     5.97   0.16    0.17    2.55       high
6     5.39   0.86    1.62    9.01     middle
7     1.20   0.03    0.01    0.31       high
8     3.19   0.08    0.01    0.45       high
9     0.02   0.03    0.01    0.10     middle
10    3.98   0.18    0.05    0.83       high
11  134.51  78.63  136.86  478.27        low
12  254.53  83.73  146.33  486.65     middle
13   15.36  86.07   13.74  185.16     middle
14   85.10  86.12   13.74  185.16     middle
15   15.12   1.37    6.09   30.12     middle

到目前为止,我使用这个丑陋的程序 "manually" 逐行检查,停在第一个类别(从高到低),大于当前值:

df["category"]="below_low"    
for i in df.index:
    for cat in ["high","middle","low"]:
        if df.loc[i,"value"]>df.loc[i,cat]:
            df.loc[i,"category"]=cat
            break

我知道 pd.cut() 方法,但我只知道如何将它与预定义的通用阈值列表一起使用。有人可以告诉我我错过了什么吗?

您可以使用:

  • 删除列 value
  • lt比较(小于)
  • 更改列的顺序
  • 累计总和列 - 首先True得到1
  • 1比较eq

mask = df.drop('value',axis=1)
         .lt(df['value'], axis=0)
         .reindex(columns=['high','middle','low'])
         .cumsum(axis=1)
         .eq(1)

如果 highmiddlelow 列中的所有值都是 False,则需要一些正确性。我通过反转 maskall.

创建新列
mask['below_low'] = (~mask).all(axis=1)
print (mask)
     high middle    low below_low
0    True  False  False     False
1   False  False  False      True
2    True  False  False     False
3   False   True  False     False
4    True  False  False     False
5    True  False  False     False
6   False   True  False     False
7    True  False  False     False
8    True  False  False     False
9   False   True   True     False
10   True  False  False     False
11  False  False   True     False
12  False   True  False     False
13  False   True   True     False
14  False   True   True     False
15  False   True  False     False

上次通话 DataFrame.idxmax:

df['category'] = mask.idxmax(axis=1)
print (df)
     value    low  middle    high   category
0   179.69  17.42   88.87  239.85       high
1     2.58  17.81   93.37  236.58  below_low
2     1.21   0.05    0.01    0.91       high
3     1.66   0.20    0.32    4.57     middle
4     3.54   0.04    0.04    0.71       high
5     5.97   0.16    0.17    2.55       high
6     5.39   0.86    1.62    9.01     middle
7     1.20   0.03    0.01    0.31       high
8     3.19   0.08    0.01    0.45       high
9     0.02   0.03    0.01    0.10     middle
10    3.98   0.18    0.05    0.83       high
11  134.51  78.63  136.86  478.27        low
12  254.53  83.73  146.33  486.65     middle
13   15.36  86.07   13.74  185.16     middle
14   85.10  86.12   13.74  185.16     middle
15   15.12   1.37    6.09   30.12     middle

多个numpy.where as pointed 的解决方案:

df['category'] = np.where(df['high'] < df['value'], 'high', 
                 np.where(df['middle'] < df['value'], 'medium',
                 np.where(df['low'] < df['value'], 'low', 'below_low')))

print (df)
     value    low  middle    high   category
0   179.69  17.42   88.87  239.85       high
1     2.58  17.81   93.37  236.58  below_low
2     1.21   0.05    0.01    0.91       high
3     1.66   0.20    0.32    4.57     medium
4     3.54   0.04    0.04    0.71       high
5     5.97   0.16    0.17    2.55       high
6     5.39   0.86    1.62    9.01     medium
7     1.20   0.03    0.01    0.31       high
8     3.19   0.08    0.01    0.45       high
9     0.02   0.03    0.01    0.10     medium
10    3.98   0.18    0.05    0.83       high
11  134.51  78.63  136.86  478.27        low
12  254.53  83.73  146.33  486.65     medium
13   15.36  86.07   13.74  185.16     medium
14   85.10  86.12   13.74  185.16     medium
15   15.12   1.37    6.09   30.12     medium

在其他所有宇宙中,您都应该使用 jezrael 经典矢量方式。但是,如果您对 apply 做事方式感到好奇,那么,您可以

In [702]: df.apply(lambda x: 'high' if x.value > x['high'] 
                        else 'middle' if x.value > x['middle'] 
                        else 'low' if x.value > x['low'] 
                        else 'below low', axis=1)
Out[702]:
0        middle
1     below low
2          high
3        middle
4          high
5          high
6        middle
7          high
8          high
9        middle
10         high
11          low
12       middle
13       middle
14       middle
15       middle
dtype: object