#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")