сохранение строк dataframe groupby ровно в две строки

#pandas #dataframe #pandas-groupby #python-3.8

#pandas #фрейм данных #pandas-groupby #python-3.8

Вопрос:

У меня есть фрейм данных, и я хочу сгруппировать строки на основе определенного столбца. Количество строк в каждой группе будет не менее 4 и не более 50. Я хочу сохранить один столбец из группы в две строки. Допустим, если размер группы четный, 2n тогда n строки в одной строке, а остальные n во второй строке. Если это нечетно, n 1 и n или n и n 1 подойдет.

Например,

 import pandas as pd
from io import StringIO

data = """
id,name
1,A
1,B
1,C
1,D
2,E
2,F
2,ds
2,G
2, dsds
"""
df = pd.read_csv(StringIO(data))
 

Я хочу, чтобы groupby id

df.groupby('id',sort=False)

а затем получите фрейм данных, подобный

     id  name
0   1   A B
1   1   C D
2   2   E F ds
3   2   G dsds
 

Комментарии:

1. ты можешь попробовать df.groupby([df.index // 2, df['id']]).agg(','.join)

2. @Manakin Мне нужны ровно строки для каждой группы. Ваше решение дает 3 строки для id 2

Ответ №1:

Возможно, это не самое эффективное решение, но оно работает:

 import numpy as np

df = df.sort_values('id')
# next 3 lines: for each group find the separation
df['range_idx'] = range(0, df.shape[0])
df['mean_rank_group'] = df.groupby(['id'])['range_idx'].transform(np.mean)
df['separate_column'] = df['range_idx'] < df['mean_rank_group']

# groupby itself with the help of additional column
df.groupby(['id', 'separate_column'], as_index=False)['name'].agg(','.join).drop(
    columns='separate_column')
 

Ответ №2:

Это немного запутанный подход, но он выполняет свою работу;

 def func(s: pd.Series):
    mid = max(s.shape[0]//2 ,1)
    l1 = ' '.join(list(s[:mid]))
    l2 = ' '.join(list(s[mid:]))
    return [l1, l2]

df_new = df.groupby('id').agg(func)

df_new["name1"]= df_new["name"].apply(lambda x: x[0])
df_new["name2"]= df_new["name"].apply(lambda x: x[1])


df = df_new.drop(labels="name", axis=1).stack().reset_index().drop(labels = ["level_1"], axis=1).rename(columns={0:"name"}).set_index("id")