Pandas groupby с пользовательской функцией для возврата значений столбца в виде массива - PullRequest
2 голосов
/ 19 апреля 2020

Я, должно быть, что-то делаю не так, но я не мог понять, что я делаю не так, даже после значительных испытаний ...

Данные:

df = pd.DataFrame({
    'ID': [3,3,3,2,2,2,1,1],
    'X': [10,11,12,20,21,30,31,32],
    'Y': [100,110,120,200,210,300,310,320]
})

# Outputs:
   ID   X    Y
0   3  10  100
1   3  11  110
2   3  12  120
3   2  20  200
4   2  21  210
5   2  30  300
6   1  31  310
7   1  32  320

вот моя функция агрегирования. (значения, разделенные запятыми, работают нормально)

def _colum_to_array(data):
    # data['Xs'] = ",".join(str(d) for d in data['X']) # works
    # data['Ys'] = ",".join(str(d) for d in data['Y']) # works

    # Next two lines causes this: Length of values does not match length of index
    # which kind of make sense.
    # data['Xs'] = [data['X'].values] 
    # data['Ys'] = [data['Y'].values] 

    # but why is this not working
    # np.tile is generating same number of array data
    data['Xs'] = np.tile([data['X'].values], (data.shape[0], 1))
    data['Ys'] = np.tile([data['Y'].values], (data.shape[0], 1))

    return data

Вот как я группируюсь:

df = df.groupby(['ID']).apply(_colum_to_array)

## Output is:
   ID   X    Y  Xs  Ys
0   3  10  100  10  10
1   3  11  110  10  10
2   3  12  120  10  10
3   2  20  200  20  20
4   2  21  210  20  20
5   2  30  300  20  20
6   1  31  310  31  31
7   1  32  320  31  31

То, что я ожидал или пытался получить, было примерно таким. Где значения столбцов X / Y будут записаны в виде массива

   ID   X    Y  Xs          Ys
0   3  10  100  [10,11,12]  [100,110,120]
1   3  11  110  [10,11,12]  [100,110,120]
2   3  12  120  [10,11,12]  [100,110,120]
3   2  20  200  [20,21,30]  [200,210,300]
4   2  21  210  [20,21,30]  [200,210,300]
5   2  30  300  [20,21,30]  [200,210,300]
6   1  31  310  [31,32]     [310,320]
7   1  32  320  [31,32]     [310,320]

Ответы [ 3 ]

2 голосов
/ 19 апреля 2020

Ваш подход на правильном пути, но проблема здесь в том, что pandas обычно не очень хорошо работает со столбцами объектов (включая списки и спискообразные типы). В особых случаях это numpy массивов внутри, поэтому вы можете только присвоить столбцы обратно, преобразовав их сначала в список с помощью .tolist():

def _colum_to_array(data):
    data['Xs'] = np.tile([data['X'].values], (data.shape[0], 1)).tolist()
    data['Ys'] = np.tile([data['Y'].values], (data.shape[0], 1)).tolist()

    return data

А затем ваш код работает:

df.groupby(['ID']).apply(_colum_to_array)

   ID   X    Y            Xs               Ys
0   3  10  100  [10, 11, 12]  [100, 110, 120]
1   3  11  110  [10, 11, 12]  [100, 110, 120]
2   3  12  120  [10, 11, 12]  [100, 110, 120]
3   2  20  200  [20, 21, 30]  [200, 210, 300]
4   2  21  210  [20, 21, 30]  [200, 210, 300]
5   2  30  300  [20, 21, 30]  [200, 210, 300]
6   1  31  310      [31, 32]       [310, 320]
7   1  32  320      [31, 32]       [310, 320]
2 голосов
/ 19 апреля 2020

Используйте groupby.agg с merge как:

df_new = df.merge(df.groupby("ID", as_index=False).agg(list)\
           .rename(columns={'X':'Xs','Y':'Ys'}))
#or with pandas 1.0.1 you can do
df_new = df.merge(df.groupby("ID").agg(Xs=('X',list), Ys=('Y',list)).reset_index())

print(df_new)
   ID   X    Y            Xs               Ys
0   3  10  100  [10, 11, 12]  [100, 110, 120]
1   3  11  110  [10, 11, 12]  [100, 110, 120]
2   3  12  120  [10, 11, 12]  [100, 110, 120]
3   2  20  200  [20, 21, 30]  [200, 210, 300]
4   2  21  210  [20, 21, 30]  [200, 210, 300]
5   2  30  300  [20, 21, 30]  [200, 210, 300]
6   1  31  310      [31, 32]       [310, 320]
7   1  32  320      [31, 32]       [310, 320]
0 голосов
/ 19 апреля 2020
x=df.groupby(['ID'])['X'].apply(list).reset_index()
y=df.groupby(['ID'])['Y'].apply(list).reset_index()
pd.merge(df,pd.merge(x,y,left_on='ID',right_on='ID'),left_on='ID',right_on='ID',suffixes=['','s'])

Объяснение: 'x' будет иметь значения списка 'Xs', 'y' будет иметь значение списка 'Ys'. Теперь объединяем эти два фрейма данных с исходным фреймом данных df и добавляем суффикс 's' для 'x' и 'y', которые оба объединены в один с внутренним оператором слияния

...