2013-08-13 1 views
2

Я борюсь с такой задачей: мне нужно дискретировать значения в столбце из фрейма данных, с определением бункеров на основе значения в другом столбце.pandas - binning с определениями бункеров на основе значения в другом столбце

Для минимального рабочего примера, позволяет определить простой dataframe:

import pandas as pd 
df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,'B' : np.random.randn(12)}) 

dataframe выглядит следующим образом:

 A  B 
0  one  2.5772143847077427 
1  one  -0.6394141654096013 
2  two  0.964652049995486 
3  three -0.3922889559403503 
4  one  1.6903991754896424 
5  one  0.5741442025742018 
6  two  0.6300564981683544 
7  three 0.9403680915507433 
8  one  0.7044433078166983 
9  one  -0.1695006646595688 
10  two  0.06376190217285167 
11  three 0.277540580579127 

Теперь я хотел бы представить столбец C, который будет содержать бункер с разными ячейками для каждого из значений в колонке A, то есть:

  • (-10,-1,0,1,10) для A == 'one',
  • (-100,0,100) для A == 'two',
  • (-999,0,1,2,3) для A == 'three'.

Желаемый результат:

 A  B  C 
0  one  2.5772143847077427  (1, 10] 
1  one  -0.6394141654096013  (-1, 0] 
2  two  0.964652049995486  (0, 100] 
3  three -0.3922889559403503  (-999, 0] 
4  one  1.6903991754896424  (1, 10] 
5  one  0.5741442025742018  (0, 1] 
6  two  0.6300564981683544  (0, 100] 
7  three 0.9403680915507433  (0, 1] 
8  one  0.7044433078166983  (0, 1] 
9  one  -0.1695006646595688  (-1, 0] 
10  two  0.06376190217285167  (0, 100] 
11  three 0.277540580579127  (0, 1] 

Я попытался с помощью pd.cut или np.digitize с различными комбинациями map, apply, но безуспешно.

В настоящее время я достижение результата путем разделения кадра и применяя pd.cut каждого подмножество по отдельности, а затем объединять, чтобы получить кадр обратно, как это:

values_in_column_A = df['A'].unique().tolist() 
bins = {'one':(-10,-1,0,1,10),'two':(-100,0,100),'three':(-999,0,1,2,3)} 

def binnize(df): 

    subdf = [] 
    for i in range(len(values_in_column_A)): 
     subdf.append(df[df['A'] == values_in_column_A[i]]) 
     subdf[i]['C'] = pd.cut(subdf[i]['B'],bins[values_in_column_A[i]]) 

    return pd.concat(subdf) 

Это работает, но я не думаю, что это достаточно изящна, я также ожидаю некоторых проблем с производительностью или памятью в производстве, когда у меня будут кадры с миллионами строк. Говоря прямо, я думаю, это можно было бы сделать лучше.

Я wolud признателен за любую помощь или идеи ...

ответ

3

ли это решит проблему?

df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3, 
        'B' : np.random.randn(12)}) 
bins = {'one': (-10,-1,0,1,10), 'two':(-100,0,100), 'three':(-999,0,1,2,3)} 

def func(row): 
    return pd.cut([row['B']], bins=bins[row['A']])[0] 

df['C'] = df.apply(func, axis=1) 

Это возвращает DataFrame:

 A   B   C 
0  one 1.440957 (1, 10] 
1  one 0.394580  (0, 1] 
2  two -0.039619 (-100, 0] 
3 three -0.500325 (-999, 0] 
4  one 0.497256  (0, 1] 
5  one 0.342222  (0, 1] 
6  two -0.968390 (-100, 0] 
7 three -0.772321 (-999, 0] 
8  one 0.803178  (0, 1] 
9  one 0.201513  (0, 1] 
10 two 1.178546 (0, 100] 
11 three -0.149662 (-999, 0] 

Faster версия binnize:

def binize2(df): 
    df['C'] = '' 
    for key, values in bins.items(): 
     mask = df['A'] == key 
     df.loc[mask, 'C'] = pd.cut(df.loc[mask, 'B'], bins=values) 

%%timeit 
df3 = binnize(df1) 
10 loops, best of 3: 56.2 ms per loop 

%%timeit 
binize2(df2) 
100 loops, best of 3: 6.64 ms per loop 

Это, вероятно, связано с тем, что она изменяет DataFrame InPlace и не создает новый.

+0

Он работает, но очень медленный (более 50 раз медленнее) ... Для DataFrame с 12k строками: 'timeit df ['C'] = df.apply (func, axis = 1)', result: '1 петли, лучше всего 3: 4,75 с за цикл' Для сравнения: 'timeit df2 = binnize (df)', result '10 loop, best of 3: 95.6 ms per loop' ... –

+0

Я предполагаю, что это может произойти из факт, что 'pd.cut' оптимизирован для работы с столбцами, а не в одиночных рядах ... –

+0

Справа, кажется, что булевские индексирование и расчет по столбцам работают намного быстрее, чем операции с строкой ... –