Подтвердить что ты не робот

Рассчитать в категориях: Эквивалент R ddply в Python?

У меня есть некоторый R-код, который мне нужен для подключения к python. Тем не менее, R magic data.frame и ddply не позволяют мне найти хороший способ сделать это в python.

Пример данных (R):

x <- data.frame(d=c(1,1,1,2,2,2),c=c(rep(c('a','b','c'),2)),v=1:6)

Пример расчета:

y <- ddply(x, 'd', transform, v2=(v-min(v))/(max(v)-min(v)))

Пример вывода:

  d c v  v2
1 1 a 1 0.0
2 1 b 2 0.5
3 1 c 3 1.0
4 2 a 4 0.0
5 2 b 5 0.5
6 2 c 6 1.0

Итак, вот мой вопрос для питонистов: как бы вы сделали то же самое? У вас есть структура данных с несколькими важными измерениями.

Для каждого (c) и каждого (d) вычислить (v-min (v))/(max (v) -min (v))) и сопоставить его с соответствующей (d, c) парой.

Не стесняйтесь использовать любые структуры данных, которые вы хотите, до тех пор, пока они быстрые на достаточно больших наборах данных (те, которые соответствуют памяти).

4b9b3361

Ответ 1

Действительно pandas является правильным (и только, я считаю) инструментом для этого в Python. Это немного менее волшебное, чем plyr, но вот как это сделать, используя функциональность groupby:

df = DataFrame({'d' : [1.,1.,1.,2.,2.,2.],
                'c' : np.tile(['a','b','c'], 2),
                'v' : np.arange(1., 7.)})
# in IPython
In [34]: df
Out[34]: 
   c  d  v
0  a  1  1
1  b  1  2
2  c  1  3
3  a  2  4
4  b  2  5
5  c  2  6

Теперь напишите небольшую функцию преобразования:

def f(group):
    v = group['v']
    group['v2'] = (v - v.min()) / (v.max() - v.min())
    return group

Обратите внимание, что это также обрабатывает NA, так как переменная v представляет собой объект pandas Series.

Теперь сгруппируйте столбец d и примените f:

In [36]: df.groupby('d').apply(f)
Out[36]: 
   c  d  v  v2 
0  a  1  1  0  
1  b  1  2  0.5
2  c  1  3  1  
3  a  2  4  0  
4  b  2  5  0.5
5  c  2  6  1  

Ответ 3

Вы также можете добиться большей производительности, если используете numpy и scipy.

Несмотря на некоторый уродливый код, он будет быстрее, путь pandas будет медленным, если количество групп очень велико и может даже быть хуже, чем R. Это всегда будет быстрее, чем R:

import numpy as np
import numpy.lib.recfunctions
from scipy import ndimage

x = np.rec.fromarrays(([1,1,1,2,2,2],['a','b','c']*2,range(1, 7)), names='d,c,v')

unique, groups = np.unique(x['d'], False, True)
uniques = range(unique.size)
mins = ndimage.minimum(x['v'], groups, uniques)[groups]
maxs = ndimage.maximum(x['v'], groups, uniques)[groups]

x2 = np.lib.recfunctions.append_fields(x, 'v2', (x['v'] - mins)/(maxs - mins + 0.0))

#save as csv
np.savetxt('file.csv', x2, delimiter=';')