2014-09-25 2 views
3

Давайте предположим, что у меня есть некоторые данные, полученные следующим образом:Нормализовать DataFrame группы

N = 20 
m = 3 
data = np.random.normal(size=(N,m)) + np.random.normal(size=(N,m))**3 

, а затем создать некоторые категоризации переменный:

indx = np.random.randint(0,3,size=N).astype(np.int32) 

и генерировать DataFrame:

import pandas as pd 
df = pd.DataFrame(np.hstack((data, indx[:,None])), 
      columns=['a%s' % k for k in range(m)] + [ 'indx']) 

Я могу получить среднее значение для каждой группы как:

df.groubpy('indx').mean() 

То, что я не знаю, как это сделать, - это вычесть среднее значение для каждой группы за каждый столбец в исходных данных, чтобы данные в каждом столбце были нормированы средним значением внутри группы. Мы ценим любые предложения.

ответ

14
In [10]: df.groupby('indx').transform(lambda x: (x - x.mean())/x.std()) 

должен это сделать.

+0

Высоких. Я просто изучаю Панды, и я еще не наткнулся на «трансформировать». Это довольно элегантно и немного быстрее, чем решение Майка. – JoshAdel

1

Хотя это не самое красивое решения, вы могли бы сделать что-то вроде этого:

indx = df['indx'].copy() 
for indices in df.groupby('indx').groups.values(): 
    df.loc[indices] -= df.loc[indices].mean() 
df['indx'] = indx 
0

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

means_stds = df.groupby('indx')['a0'].agg(['mean','std']).reset_index() 
df = df.merge(means_stds,on='indx') 
df['a0_normalized'] = (df['a0'] - df['mean'])/df['std'] 

Чтобы сделать это для нескольких столбцов вам придется разобраться в слиянии. Мое предложение было бы сгладить мультииндексных столбцы из агрегации, как в this answer, а затем объединить и нормализует для каждой колонки отдельно:

means_stds = df.groupby('indx')[['a0','a1']].agg(['mean','std']).reset_index() 
means_stds.columns = ['%s%s' % (a, '|%s' % b if b else '') for a, b in means_stds.columns] 
df = df.merge(means_stds,on='indx') 
for col in ['a0','a1']: 
    df[col+'_normalized'] = (df[col] - df[col+'|mean'])/df[col+'|std'] 
Смежные вопросы