2016-03-17 3 views
3

Я хотел бы создать новый dataframe из результатов groupby на другом. Результат должен иметь одну строку на группу (в основном, векторный снимок карты), а новые имена столбцов не имеют никакого отношения к существующим именам. Это кажется естественным использованием для agg, но, похоже, это создает существующие столбцы.Создайте совершенно новый DataFrame эффективно из groupby .agg() или .apply() в Pandas?

d = pd.DataFrame({'a': [0,0,1,1], 'b': [3,4,5,6], 'c': [7,8,9,0]}) 

    a b c 
0 0 3 7 
1 0 4 8 
2 1 5 9 
3 1 6 0 

agg() создаст новые столбцы с Серия:

d.groupby('a')['b'].agg({'x': lambda g: g.sum()}) 

    x 
a  
0 7 
1 11 

Но удручающе не с DataFrame:

d.groupby('a').agg({'x': lambda g: g.b.sum()}) 
KeyError: 'x' 

я могу это сделать, возвращая один двухрядный DataFrame из apply() :

d.groupby('a').apply(lambda g: pd.DataFrame([{'x': g.b.mean(), 'y': (g.b * g.c).sum()}])).reset_index(level=1, drop=True) 

    x y 
a   
0 3.5 53 
1 5.5 45 

, но это некрасиво и, как вы можете себе представить, создание нового dict, list и DataFrame для каждой строки медленнее даже для входов с небольшим размером.

+1

Может быть, ответ парфе здесь также будет работать для вас: http://stackoverflow.com/questions/35938393/pandas-aggregating-multiple-columns-with-multiple-functions/35944697#35944697 – JohnE

ответ

0

Вот это сравнение несколько различных способов сделай это. Я предпочитаю возвращать Серию; разумно кратким, ясным и эффективным. Благодаря @Siraj S для вдохновения.

df = pd.DataFrame(np.random.rand(1000000, 5), columns=list('abcde')) 
grp = df.groupby((df.a * 100).astype(int)) 


%timeit grp.apply(lambda g: pd.DataFrame([{'n': g.e.count(), 'x': (g.b * g.c).sum()/g.c.sum(), 'y': g.d.mean(), 'z': g.e.std()}])).reset_index(level=1, drop=True) 
1 loop, best of 3: 328 ms per loop 

%timeit grp.apply(lambda g: (g.e.count(), (g.b * g.c).sum()/g.c.sum(), g.d.mean(), g.e.std())).apply(pd.Series) 
1 loop, best of 3: 266 ms per loop 

%timeit grp.apply(lambda g: pd.Series({'n': g.e.count(), 'x': (g.b * g.c).sum()/g.c.sum(), 'y': g.d.mean(), 'z': g.e.std()})) 
1 loop, best of 3: 265 ms per loop 

%timeit grp.apply(lambda g: {'n': g.e.count(), 'x': (g.b * g.c).sum()/g.c.sum(), 'y': g.d.mean(), 'z': g.e.std()}).apply(pd.Series) 
1 loop, best of 3: 273 ms per loop 

%timeit pd.concat([grp.apply(lambda g: g.e.count()), grp.apply(lambda g: (g.b * g.c).sum()/g.c.sum()), grp.apply(lambda g: g.d.mean()), grp.apply(lambda g: g.e.std())], axis=1) 
1 loop, best of 3: 708 ms per loop 
0

может быть, это может помочь

df = d.groupby('a')[['b','c']].sum() 
df.index.name = None 
df.columns=['b_sum','c_sum'] 

или если вы хотите, чтобы вычислить отдельные статистические данные по отдельным столбцам, вы можете сделать что-то вроде этого

df = d.groupby('a')[['b','c']].apply(lambda x: (x.b.mean(),x.c.sum())).apply(pd.Series) 
+0

даже это, кажется, работать, если вы хотите выполнять разные функции в разных столбцах (например, b.mean() и c.sum()) df = d.groupby ('a') [['b', 'c']]. (lambda x: (xbmean(), xcsum())] df = df.apply (pd.Series) –

+0

или более непосредственно df = d.groupby ('a') [['b', ' c ']] применить (lambda x: (xbmean(), xcsum())). apply (pd.Series) –

+0

Вы действительно должны [редактировать] дополнительную информацию в свой ответ, а не придерживаться на комментариях, которые невозможно прочитать. – Ajean

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