Pandas: изменение формы данных - PullRequest
2 голосов
/ 01 апреля 2020

У меня есть вопрос, связанный с пандой. Мой фрейм данных выглядит примерно так:

  id val1 val2
0  1     0    1
1  1     1    0
2  1     0    0
3  2     1    1
4  2     1    1
5  2     1    0
6  3     0    0
7  3     0    1
8  3     1    1
9  4     1    0
10 4     0    1
11 4     0    0

Я хочу преобразовать его в нечто вроде:

             a         b        c
   id     a0   a1   b0   b1   c0   c1
    1     0    1    1    0    0    0
    2     1    1    1    1    1    0
    3     0    0    1    1    1    1
    4     1    0    0    1    0    0

Я думал о чем-то вроде добавления столбца sub_id, который циклически перечисляется с помощью b и c, а затем сделайте unstack кадра. Есть ли более простое / разумное решение?

Большое спасибо!

Тим

Ответы [ 2 ]

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

Если возможно, вместо чисел abc используется GroupBy.cumcount для счетчика, создать MultiIndex с помощью DataFrame.set_index и изменить его на DataFrame.unstack и последняя сортировка второго уровня с DataFrame.swaplevel:

g = df.groupby('id').cumcount()

df = df.set_index(['id', g]).unstack().sort_index(axis=1, level=1).swaplevel(0,1,axis=1)
print (df)
      0         1         2     
   val1 val2 val1 val2 val1 val2
id                              
1     0    1    1    0    0    0
2     1    1    1    1    1    0
3     0    0    0    1    1    1
4     1    0    0    1    0    0

Если возможно значение a,b,c, можно сгенерировать словарь из string.ascii_lowercase и rename столбцов:

import string

d = dict(enumerate(string.ascii_lowercase))
df = df.rename(columns=d)
print (df)
      a         b         c     
   val1 val2 val1 val2 val1 val2
id                              
1     0    1    1    0    0    0
2     1    1    1    1    1    0
3     0    0    0    1    1    1
4     1    0    0    1    0    0

Решение для переименования обоих уровней - сначала создать имена столбцов по умолчанию по диапазону после set_index:

g = df.groupby('id').cumcount()
df = df.set_index(['id', g])
df.columns = range(len(df.columns))
df = df.unstack().sort_index(axis=1, level=1).swaplevel(0,1,axis=1)
print (df)
    0     1     2   
    0  1  0  1  0  1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0

И, наконец, в списке понимания установить новые значения:

import string

d = dict(enumerate(string.ascii_lowercase))
df.columns = pd.MultiIndex.from_tuples([(d[a], f'{d[a]}{b}') for a, b in df.columns])
print (df)
    a     b     c   
   a0 a1 b0 b1 c0 c1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0
0 голосов
/ 01 апреля 2020

Одно из возможных решений:

Начните с переформатирования значений для каждого id в одну строку:

res = df.set_index('id').groupby('id').apply(
    lambda grp: pd.Series(grp.values.flatten()))

На данный момент результат таков:

    0  1  2  3  4  5
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0

Затем задайте правильные имена столбцов:

res.columns = pd.MultiIndex.from_tuples(
    [(x, x + y) for x in list('abc') for y in list('01')])

Окончательный результат:

    a     b     c   
   a0 a1 b0 b1 c0 c1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...