агрегат панды по функциям - PullRequest
0 голосов
/ 24 августа 2018

У меня есть данные, как показано ниже:

id  movie   details value
5   cane1   good    6
5   wind2   ok  30.3
5   wind1   ok  18
5   cane1   good    2
5   cane22  ok  4
5   cane34  good    7
5   wind2   ok  2

Я хочу вывод с критериями ниже:

Если название фильма начинается с «трости» - суммируйте значение

Если название фильма начинается с «ветра» - подсчитайте вхождение.

Итак - окончательный результат будет:

id  movie   value
5   cane1   8
5   cane22  4
5   cane34  7
5   wind1   1
5   wind2   2

Я пытался использовать:

movie_df.groupby(['id']).apply(aggr)

def aggr(x):
    if x['movie'].str.startswith('cane'):
        y = x.groupby(['value']).sum()

    else:
         y = x.groupby(['movie']).count()

    return y

Но это не работает. Может кто-нибудь помочь, пожалуйста?

Ответы [ 4 ]

0 голосов
/ 24 августа 2018

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

df['group'] = df.movie.transform(lambda x : x[:4])

Следующим шагом будет группировка по этому столбцу

df.groupby('group').apply(agg_fun)

с использованием следующей функции агрегирования

def agg_fun(grp):
    if grp.name == "cane":
        value=grp.value.sum()
    else:
        value=grp.value.count()
    return value

Вывод этого кода

group
cane    19.0
wind     3.0
0 голосов
/ 24 августа 2018

Вы должны стремиться к векторизованным операциям, где это возможно.

Вы можете вычислить 2 результата и затем объединить их.

mask = df['movie'].str.startswith('cane')

df1 = df[mask].groupby('movie')['value'].sum()
df2 = df[~mask].groupby('movie').size()

res = pd.concat([df1, df2], ignore_index=0)\
        .rename('value').reset_index()

print(res)

    movie  value
0   cane1    8.0
1  cane22    4.0
2  cane34    7.0
3   wind1    1.0
4   wind2    2.0
0 голосов
/ 24 августа 2018

Там может быть несколько способов сделать это.Один из способов - сначала отфильтровать по названию фильма, а затем объединить и объединить.

cane = movie_df[movie_df['movie'].str.startswith('cane1')]
wind = movie_df[movie_df['movie'].str.startswith('wind')]

cane_sum = cane.groupby(['id']).agg({'movie':'first', 'value':'sum'}).reset_index()
wind_count = wind.groupby(['id']).agg({'movie':'first', 'value':'count'}).reset_index()

pd.concat([cane_sum, wind_count])
0 голосов
/ 24 августа 2018

Прежде всего, вам нужно выполнить строковую операцию.Я полагаю, в вашем случае вам не нужны цифры в названии фильма.Используйте решение, обсуждаемое в пандах, применяя регулярное выражение для замены значений .Затем вы вызываете groupby () для новой серии.

К вашему сведению: некоторые названия фильмов имеют только цифры;в этом случае вам нужно использовать функцию обновления.https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.update.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...