Панды - Как сделать 'сгруппировать' по нескольким столбцам в зависимости от условий? - PullRequest
1 голос
/ 26 июня 2019

Я застрял в группировании нескольких столбцов, используя различные условия:

Мой фрейм данных выглядит так:

code    product brand   lvl1    lvl2    lvl3     lvl4   lvl5        price
8968653 ABC             Milk    Mother  Toddler         Porridge    69
8968653 ABC     AB              Baby                    Bayi        95

Код и Product_name являются общими полями. Все остальные столбцы должны быть сгруппированы согласно следующим условиям:

  1. Обе ячейки пусты: показать NaN

  2. Одна ячейка пуста: показать другое значение

  3. Обе ячейки не пусты: объедините ячейки по трубе

  4. Столбец цены должен показывать среднее значение

Ожидаемый результат:

code    product brand   lvl1 lvl2        lvl3     lvl4  lvl5         price
8968653 ABC     AB      Milk Mother|Baby Toddler  NaN   Porridge|Bayi    82

Ответы [ 3 ]

3 голосов
/ 26 июня 2019

Мы можем сделать это в несколько шагов:

  1. Сначала мы получаем список столбцов типа string и numeric
  2. Во-вторых, мы используем groupby.agg или groupby.mean в зависимости от того, есть ли у нас столбцы string или numeric:
  3. Мы очищаем наш фрейм данных, где есть ненужные |.
# Step 1 get string and numeric columns
str_cols = df.iloc[:, 2:-1].columns
num_cols = df.iloc[:, -1:].columns

# Step 2 groupby on string and numeric columns
d1 = df.groupby(['code','product'])[str_cols].agg('|'.join)
d2 = df.groupby(['code', 'product'])[num_cols].mean()

# Join the dataframe back as 1
df = d1.join(d2).reset_index()

Выход 1:

      code product brand   lvl1         lvl2      lvl3 lvl4           lvl5  price
0  8968653     ABC   |AB  Milk|  Mother|Baby  Toddler|    |  Porridge|Bayi     82

Теперь мы очищаем наш фрейм данных, удаляя каналы |.

df = df.replace('(^\||\b\|\b|\|$)', '', regex=True)

Конечный выход

      code product brand  lvl1         lvl2     lvl3 lvl4           lvl5  price
0  8968653     ABC    AB  Milk  Mother|Baby  Toddler       Porridge|Bayi     82
2 голосов
/ 26 июня 2019

Вам нужно определить функцию:

def f(x):
    if x.isna().all():
        return np.nan
    x = x.dropna()
    if x.dtype == 'int64':
        return x.mean()
    x = x.drop_duplicates()
    if len(x)>1:
        return '|'.join(x)
    return x


df.replace('', np.nan).groupby(['code'], as_index=False).agg(f)

Выход:

      code product brand  lvl1         lvl2     lvl3  lvl4           lvl5  price
0  8968653     ABC    AB  Milk  Mother|Baby  Toddler   NaN  Porridge|Bayi     82
1 голос
/ 26 июня 2019

Аналогично Эрфану, но выстраиваете агг, поэтому группировать нужно всего один раз:

# dictate which column does what
str_cols = [col for col in df.columns if col not in ['code','product', 'price']]
agg = {col:'|'.join for col in str_cols}
agg['price'] = 'mean'

# aggregation
new_df = df.groupby(['code','product'],as_index=False).agg(agg)

# strip by columns
# replace would be a better choice, but that'll be copied from Efran's
new_df[str_cols] = new_df[str_cols].apply(lambda x: x.str.strip('\|'))

Вывод:

    code    product brand   lvl1    lvl2        lvl3    lvl4    lvl5            price
0   8968653 ABC     AB      Milk    Mother|Baby Toddler         Porridge|Bayi   82.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...