2016-08-26 5 views
6

У меня больше опыта с R's data.table, но я пытаюсь узнать pandas. В data.table, я могу сделать что-то вроде этого:pandas: как выполнять несколько операций с групповым применением

> head(dt_m) 
    event_id   device_id longitude latitude    time_ category 
1: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
2: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
3: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
4: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
5: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
6: 1004583 -100015673884079572  NA  NA 1970-01-01 06:34:52 1 free 
       app_id is_active 
1: -5305696816021977482   0 
2: -7164737313972860089   0 
3: -8504475857937456387   0 
4: -8807740666788515175   0 
5: 5302560163370202064   0 
6: 5521284031585796822   0 


dt_m_summary <- dt_m[, 
        .(
         mean_active = mean(is_active, na.rm = TRUE) 
         , median_lat = median(latitude, na.rm = TRUE) 
         , median_lon = median(longitude, na.rm = TRUE) 
         , mean_time = mean(time_) 
         , new_col = your_function(latitude, longitude, time_) 
        ) 
        , by = list(device_id, category) 
        ] 

Новые колонки (mean_active через new_col), а также device_id и category, появится в dt_m_summary. Я мог бы также сделать подобное by преобразование в исходной таблице, если я хочу новый столбец результатов GroupBy применить:

dt_m[, mean_active := mean(is_active, na.rm = TRUE), by = list(device_id, category)]

(в случае, если я хотел, например, чтобы выбрать строки, где mean_active превышает некоторый порог или делает что-то еще).

Я знаю, что есть groupby в pandas, но я не нашел способ сделать вид простых преобразований, как указано выше. Лучшее, что я мог придумать, это сделать серию groupby-apply's, а затем объединить результаты в один dataframe, но это кажется очень неуклюжим. Есть ли лучший способ сделать это?

ответ

6

IIUC, используйте groupby и agg. См. docs для получения дополнительной информации.

df = pd.DataFrame(np.random.rand(10, 2), 
        pd.MultiIndex.from_product([list('XY'), range(5)]), 
        list('AB')) 

df 

enter image description here

df.groupby(level=0).agg(['sum', 'count', 'std']) 

enter image description here


более с учетом примера можно привести

# level=0 means group by the first level in the index 
# if there is a specific column you want to group by 
# use groupby('specific column name') 
df.groupby(level=0).agg({'A': ['sum', 'std'], 
         'B': {'my_function': lambda x: x.sum() ** 2}}) 

enter image description here

Примечаниеdict передается методу agg имеет ключи 'A' и 'B'. Это означает, что запускать функции ['sum', 'std'] для 'A' и lambda x: x.sum() ** 2 для 'B' (и пометить его 'my_function')

Примечание 2, относящиеся к вашему new_column. agg требует, чтобы переданные функции уменьшали столбцы до скаляров. Вы лучше добавить новую колонку перед groupby/agg

+1

Не забудьте лямбда.'new_col = your_function (широта, долгота, время_)' – Alexander

+0

Итак, как бы назвал бы 'my_function' принятие нескольких аргументов? Представьте, что это долгая функция с кучей линий. –

+0

Проблема, которую я вижу, заключается в том, что в моей работе редко бывает, что только одна переменная преобразуется некоторой функцией. Обычно мне не нужно найти сумму только А. У меня есть функция, которая может занимать несколько столбцов данных. Затем мне нужно, чтобы результаты этой функции применялись к агрегированным строкам (похожие на X и Y) и имеют выбор для вызова столбцов. Вы говорите, что мне нужно предварительно генерировать столбцы в новом фреймворке данных, а затем ... что? –

0

@piRSquared имеет большой ответ, но в вашем конкретном случае, я думаю, вы могли бы быть заинтересованы в использовании панд очень гибкие apply function. Поскольку он может применяться к каждой группе по одному, вы можете одновременно работать с несколькими столбцами внутри сгруппированного DataFrame.

def your_function(sub_df): 
    return np.mean(np.cos(sub_df['latitude']) + np.sin(sub_df['longitude']) - np.tan(sub_df['time_'])) 

def group_function(g): 
    return pd.Series([g['is_active'].mean(), g['latitude'].median(), g['longitude'].median(), g['time_'].mean(), your_function(g)], 
        index=['mean_active', 'median_lat', 'median_lon', 'mean_time', 'new_col']) 

dt_m.groupby(['device_id', 'category']).apply(group_function) 

Однако, я определенно согласен с @piRSquared, что было бы очень полезно увидеть полный пример, включая ожидаемый результат.

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

  • Нет связанных вопросов^_^