Вы также можете создать моноидный класс, который объединяет два списка, добавляя ко второму последнее значение из первого. Нет мутаций и не сгибов:
класс case CumSum (v: List [Int]) {def + (o: CumSum) = CumSum (v ::: (ov map (_ + v .last)))} определенный класс CumSum scala & gt; Список (1,2,3,4,5,6) map {v = & gt; CumSum (Список (v))} уменьшить (_ + _) res27: CumSum = CumSum (список (1, 3, 6, 10, 15, 21))
Для первой части вы можете передать имя столбца для ключей и список функций для значений:
In [28]: df
Out[28]:
A B C D E GRP
0 0.395670 0.219560 0.600644 0.613445 0.242893 0
1 0.323911 0.464584 0.107215 0.204072 0.927325 0
2 0.321358 0.076037 0.166946 0.439661 0.914612 1
3 0.133466 0.447946 0.014815 0.130781 0.268290 1
In [26]: f = {'A':['sum','mean'], 'B':['prod']}
In [27]: df.groupby('GRP').agg(f)
Out[27]:
A B
sum mean prod
GRP
0 0.719580 0.359790 0.102004
1 0.454824 0.227412 0.034060
UPDATE 1:
Поскольку агрегатная функция работает над Series, ссылки на другие имена столбцов теряются. Чтобы обойти это, вы можете ссылаться на полный фреймворк и индексировать его с помощью индексов группы в лямбда-функции.
Вот хакерский способ обхода:
In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}
In [69]: df.groupby('GRP').agg(f)
Out[69]:
A B D
sum mean prod <lambda>
GRP
0 0.719580 0.359790 0.102004 1.170219
1 0.454824 0.227412 0.034060 1.182901
Здесь результирующий ' D 'состоит из суммированных значений «E».
UPDATE 2:
Вот такой метод, который, я думаю, сделает все, что вы просите. Сначала создайте пользовательскую лямбда-функцию. Ниже, g ссылается на группу. При агрегировании g будет Серией. Передача g.index
в df.ix[]
позволяет выбрать текущую группу из df. Затем я тестирую, если столбец C меньше 0,5. Возвращенная логическая серия передается в g[]
, которая выбирает только те строки, которые соответствуют критериям.
In [95]: cust = lambda g: g[df.loc[g.index]['C'] < 0.5].sum()
In [96]: f = {'A':['sum','mean'], 'B':['prod'], 'D': {'my name': cust}}
In [97]: df.groupby('GRP').agg(f)
Out[97]:
A B D
sum mean prod my name
GRP
0 0.719580 0.359790 0.102004 0.204072
1 0.454824 0.227412 0.034060 0.570441
Ответ Теда потрясающий. Я закончил тем, что использовал меньшую версию, если кто-то заинтересован. Полезно, если вы ищете одно агрегирование, которое зависит от значений из нескольких столбцов:
df=pd.DataFrame({'a': [1,2,3,4,5,6], 'b': [1,1,0,1,1,0], 'c': ['x','x','y','y','z','z']})
a b c
0 1 1 x
1 2 1 x
2 3 0 y
3 4 1 y
4 5 1 z
5 6 0 z
df.groupby('c').apply(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
c
x 2.0
y 4.0
z 5.0
Мне нравится этот подход, поскольку я все еще могу использовать агрегат. Возможно, люди скажут мне, почему применение необходимо для получения нескольких столбцов при выполнении группировок по группам.
Теперь это кажется очевидным, но пока вы не выбираете интересующий столбец напрямую после groupby у вас будет доступ ко всем столбцам фреймворка из вашей функции агрегации.
df.groupby('c')['a'].aggregate(lambda x: x[x>1].mean())
df.groupby('c').aggregate(lambda x: x[(x['a']>1) & (x['b']==1)].mean())['a']
df.groupby('c').aggregate(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
Надеюсь, это поможет.
Вторая половина принятого в настоящее время ответа устарела и имеет два отклонения. Прежде всего, вы больше не можете передавать словарь словарей в метод agg
groupby. Во-вторых, никогда не используйте .ix
.
Если вы хотите работать с двумя отдельными столбцами одновременно, я бы предложил использовать метод apply
, который implicity передает DataFrame к прикладной функции. Давайте используем аналогичный блок данных, как тот, что приведен выше
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df
a b c d group
0 0.418500 0.030955 0.874869 0.145641 0
1 0.446069 0.901153 0.095052 0.487040 0
2 0.843026 0.936169 0.926090 0.041722 1
3 0.635846 0.439175 0.828787 0.714123 1
Словарь, сопоставленный с именами столбцов, для функций агрегации, по-прежнему отлично подходит для выполнения агрегации.
df.groupby('group').agg({'a':['sum', 'max'],
'b':'mean',
'c':'sum',
'd': lambda x: x.max() - x.min()})
a b c d
sum max mean sum <lambda>
group
0 0.560541 0.507058 0.418546 1.707651 0.129667
1 0.187757 0.157958 0.887315 0.533531 0.652427
Если вам не нравится это уродливое имя столбца лямбда, вы можете использовать обычную функцию и указать специальное имя для специального атрибута __name__
следующим образом:
def max_min(x):
return x.max() - x.min()
max_min.__name__ = 'Max minus Min'
df.groupby('group').agg({'a':['sum', 'max'],
'b':'mean',
'c':'sum',
'd': max_min})
a b c d
sum max mean sum Max minus Min
group
0 0.560541 0.507058 0.418546 1.707651 0.129667
1 0.187757 0.157958 0.887315 0.533531 0.652427
apply
и возвращая серию Теперь, если у вас было несколько столбцов, которые должны были взаимодействовать друг с другом, вы не можете использовать agg
, который неявно передает Серию в агрегирующую функцию. При использовании apply
вся группа в качестве DataFrame передается в функцию.
Я рекомендую сделать одну настраиваемую функцию, которая возвращает Серию всех агрегатов. Используйте индекс Series в качестве меток для новых столбцов:
def f(x):
d = {}
d['a_sum'] = x['a'].sum()
d['a_max'] = x['a'].max()
d['b_mean'] = x['b'].mean()
d['c_d_prodsum'] = (x['c'] * x['d']).sum()
return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])
df.groupby('group').apply(f)
a_sum a_max b_mean c_d_prodsum
group
0 0.560541 0.507058 0.418546 0.118106
1 0.187757 0.157958 0.887315 0.276808
Если вы любите MultiIndexes, вы все равно можете вернуть серию с такими же:
def f_mi(x):
d = []
d.append(x['a'].sum())
d.append(x['a'].max())
d.append(x['b'].mean())
d.append((x['c'] * x['d']).sum())
return pd.Series(d, index=[['a', 'a', 'b', 'c_d'],
['sum', 'max', 'mean', 'prodsum']])
df.groupby('group').apply(f_mi)
a b c_d
sum max mean prodsum
group
0 0.560541 0.507058 0.418546 0.118106
1 0.187757 0.157958 0.887315 0.276808
a
в группе 0
, если это не будет 0.418500 + 0.446069 = 0.864569
? То же самое справедливо и для других ячеек, цифры, похоже, не складываются. Может быть, это несколько иной базовый фрейм, который использовался в последующих примерах?
– slackline
14 June 2018 в 13:26
{funcname: func}
как значения вместо списков, чтобы сохранить свои собственные имена. Но в любом случае я не могу передатьlambda
, который использует другие столбцы (например,lambda x: x['D'][x['C'] < 3].sum()
выше: & quot; KeyError: 'D' & quot;). Любая идея, если это возможно? – beardc 25 January 2013 в 22:56KeyError: 'D'
– Zelazny7 25 January 2013 в 22:57{'D': {'my name':lambda function}}
, и он сделает внутреннюю клавишу dict именем столбца. – Zelazny7 25 January 2013 в 23:27