2017-02-15 14 views
1

У меня есть dataframe с некоторыми числовыми значениями, хранящихся в столбце «значение» в сопровождении своих категорических tresholds (предупреждение уровней в данном случае), которые хранятся в других столбцах (в моем случае «низкий», «средний», «высокий»):категоризация Панда колонок с indiviual пользовательских бункеров (tresholds)

 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 

Я хотел бы знать, в какой категории относится каждое значение (например, первое значение будет среднего, се cond будет ниже_low, так как он меньше, чем любой из его пунктов, третий будет высокий, ... вы получите идею). Так вот ожидаемый выход:

 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 

До сих пор я использую эту уродливую процедуру «вручную» проверка построчно, остановка на первой категории (от высшего к низшему), будучи больше, что текущее значение:

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(), но я только знаю, как использовать его с заданным списком родового tresholds. Может ли кто-нибудь сказать, что мне не хватает?

+1

я рекомендую набор вложенных вызовов 'numpy.where' –

ответ

5

Вы можете использовать:

  • удалить столбец 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) 

Если все значения в столбцах high, middle и low являются False то некоторая правильность необходимо. Я создаю новую колонку с инвертированием mask и all.

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, как отметило Paul H:

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 
+0

Вы природное чудо, jezrael! :) Хотя, это похоже на довольно продвинутое решение, казалось бы, простой задачи.По крайней мере, я успокоился, что я не пропустил какое-то неудобно прямое использование pd.cut() ... Спасибо! –

+1

Это золотая витрина для векторных операций! +1 Сэр. – Zero

1

В любой другой вселенной, вы должны использовать 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 
+0

Спасибо, Джон за то, что он хорош для новичков :)! На данный момент мне гораздо легче понять применение подобных решений. Эти векторные операции кажутся мне настолько неинтуитивными ... :( –

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

  • Нет связанных вопросов^_^