pandas: создавать разные типы агрегации для одного и того же столбца [duplicate]

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

  класс 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))  
101
задан beardc 25 January 2013 в 22:26
поделиться

3 ответа

Для первой части вы можете передать имя столбца для ключей и список функций для значений:

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
139
ответ дан RK1 16 August 2018 в 01:57
поделиться
  • 1
    Интересно, что я также могу передать dict {funcname: func} как значения вместо списков, чтобы сохранить свои собственные имена. Но в любом случае я не могу передать lambda, который использует другие столбцы (например, lambda x: x['D'][x['C'] < 3].sum() выше: & quot; KeyError: 'D' & quot;). Любая идея, если это возможно? – beardc 25 January 2013 в 22:56
  • 2
    Я пытался сделать именно это, и я получаю ошибку KeyError: 'D' – Zelazny7 25 January 2013 в 22:57
  • 3
    Вы можете передать dict для значения столбца {'D': {'my name':lambda function}}, и он сделает внутреннюю клавишу dict именем столбца. – Zelazny7 25 January 2013 в 23:27
  • 4
    Я считаю, что pandas теперь поддерживает несколько функций, применяемых к сгруппированному файлу данных: pandas.pydata.org/pandas-docs/stable/… – IanS 20 May 2016 в 08:44
  • 5
    Это очень полезно! – michel 25 August 2016 в 15:14

Ответ Теда потрясающий. Я закончил тем, что использовал меньшую версию, если кто-то заинтересован. Полезно, если вы ищете одно агрегирование, которое зависит от значений из нескольких столбцов:

создает группировку данных

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())

Надеюсь, это поможет.

0
ответ дан campo 16 August 2018 в 01:57
поделиться

Вторая половина принятого в настоящее время ответа устарела и имеет два отклонения. Прежде всего, вы больше не можете передавать словарь словарей в метод 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
49
ответ дан Ted Petrou 16 August 2018 в 01:57
поделиться
  • 1
    Мне нравится шаблон использования функции, которая возвращает серию. Очень аккуратный. – Stephen McAteer 19 December 2017 в 00:07
  • 2
    это единственный способ, которым я обнаружил, что агрегировать фрейм данных несколькими входами столбцов одновременно (пример c_d выше) – Blake 24 January 2018 в 00:11
  • 3
    Красивый ответ. Спасибо. – Robert Muil 21 February 2018 в 19:38
  • 4
    Я смущен результатами, взяв суммирование a в группе 0, если это не будет 0.418500 + 0.446069 = 0.864569? То же самое справедливо и для других ячеек, цифры, похоже, не складываются. Может быть, это несколько иной базовый фрейм, который использовался в последующих примерах? – slackline 14 June 2018 в 13:26
Другие вопросы по тегам:

Похожие вопросы: