pyjanitor-devs/pyjanitor

Feature Proposal: Auto Agg method

Open

#732 创建于 2020年9月4日

在 GitHub 查看
 (9 评论) (0 反应) (1 负责人)Python (164 fork)batch import
being worked onenhancementgood first issuegood intermediate issuehacktoberfest

仓库指标

Star
 (1,217 star)
PR 合并指标
 (平均合并 2天 12小时) (30 天内合并 4 个 PR)

描述

Brief Description

An auto_agg method where you just put the columns you want and it automatically aggregates the dataframe.

For example, I could do something like:

df.auto_agg(['state', 'age_mean'])

On a dataframe that has a state and age column and it will automatically get the average age by state.

Example API

Here's some basic code:


import pandas as pd

colnames = ('id', 'state', 'state_abbr', 'amount')

df = pd.DataFrame.from_records((
	('Person1', 'California', 'CA', 20),
	('Person2', 'California', 'CA', 30),
	('Person3', 'New York', 'NY', 15),
	('Person4', 'New York', 'NY', 10),
	('Person5', 'New York', 'NY', 45)), columns=colnames)


new_columns = ['state_abbr', 'state_count']


def flatten_dict(x):
    return {k: v for d in x for k, v in d.items()}


def auto_agg(df, new_columns):
    cols = set(df.columns)
    new_columns_set = set(new_columns)
    group_cols = cols.intersection(new_columns_set)
    agg_cols = new_columns_set.difference(cols)
    agg_groups = [{col: agg_col} for col in cols for agg_col in agg_cols if agg_col.startswith(col)]
    this_dict = dict()
    for i in agg_groups:
        value = list(i.values())[0]
        key = list(i.keys())[0]
        this_dict[value] = ''
        current_value = this_dict.get(value)
        if len(key) > len(current_value):
            this_dict[value] = key
    agg_groups_rename = dict([(value, key) for key, value in this_dict.items()])  
    agg_groups_agg = [{i[0]: i[1].split(i[0])[1:][0][1:]} for i in agg_groups_rename.items()]
    agg_groups_agg = flatten_dict(agg_groups_agg)
    group_cols_list = list(group_cols)
    return df.groupby(group_cols_list, as_index=False).agg(agg_groups_agg).rename(columns=agg_groups_rename)


auto_agg(df, new_columns)

There's a problem when column names are subsets of eachother, which is why I have an example with state_abbr and state. Sometimes the set math gets confused when trying to split the column names and the functions.

I think a basic workaround would be to be able to "force" the functions on specific columns without us needing to guess, like this:

new_columns = ['state', 'amount_sum', {'id': 'count'}]
auto_agg(df, new_columns)
# or df.auto_agg(new_columns)

If we say something like "if your choice of columns mess up, then be explicit" we might not need this part of the code, since we won't need to find the biggest or smallest version of the column name.

for i in agg_groups:
        value = list(i.values())[0]
        key = list(i.keys())[0]
        this_dict[value] = ''
        current_value = this_dict.get(value)
        if len(key) > len(current_value):
            this_dict[value] = key

贡献者指南