Я пытаюсь сгенерировать особенно структурированный фрейм данных, но я не могу "складывать" данные. Мой пример необработанных данных:

# raw data
df = pd.DataFrame({'Name':['name1', 'name2', 'name3', 'name1', 'name2', 'name3', 'name1', 'name2', 'name3' ], 
                   'Year':['freshman','sophomore','freshman', 'freshman','sophomore','freshman', 'freshman','sophomore','freshman'], 
                   'Rotation':['ERJD','PEDI','MAM','PEDI', 'ERJD','PEDI','MAM','ERJD','ABD'],
                   'Week1':[1,1,1,0,0,0,0,0,0],
                   'Week2':[0,0,0,1,1,1,0,0,0],
                   'Week3':[0,0,0,0,0,0,1,1,1],
                   'Week4':[1,0,0,0,0,0,0,1,1]
                  })
df = df[['Name','Year','Rotation','Week1','Week2','Week3','Week4']]

Что выглядит так:

    Name    Year    Rotation    Week1   Week2   Week3   Week4
0   name1   freshman    ERJD      1       0       0       1
1   name2   sophomore   PEDI      1       0       0       0
2   name3   freshman    MAM       1       0       0       0
3   name1   freshman    PEDI      0       1       0       0
4   name2   sophomore   ERJD      0       1       0       0
5   name3   freshman    PEDI      0       1       0       0
6   name1   freshman    MAM       0       0       1       0
7   name2   sophomore   ERJD      0       0       1       1
8   name3   freshman    ABD       0       0       1       1

Я изменяю структуру данных:

#Reshape Table + Filtering
df = pd.melt(df, 
             id_vars=['Name','Year','Rotation'], 
             value_vars=list(df.columns[3:]),
             var_name='Week', 
             value_name='Sum of Value')

df = df.loc[df['Sum of Value'] == 1].reset_index()
df.pop('index')

Что генерирует:

    Name    Year    Rotation    Week    Sum of Value
0   name1   freshman    ERJD    Week1       1
1   name2   sophomore   PEDI    Week1       1
2   name3   freshman    MAM     Week1       1
3   name1   freshman    PEDI    Week2       1
4   name2   sophomore   ERJD    Week2       1
5   name3   freshman    PEDI    Week2       1
6   name1   freshman    MAM     Week3       1
7   name2   sophomore   ERJD    Week3       1
8   name3   freshman    ABD     Week3       1
9   name1   freshman    ERJD    Week4       1
10  name2   sophomore   ERJD    Week4       1
11  name3   freshman    ABD     Week4       1

Я создаю сводную таблицу:

#Create Pivot
pivot = df.pivot_table(index=['Rotation','Year'], columns='Week', values='Name', aggfunc=lambda x: ' '.join(x))
pivot = pivot.reindex(weeks, axis=1) # Change order of Columns
pivot

Что генерирует:

                    Week1       Week2      Week3    Week4
Rotation    Year                
ABD       freshman   None        None      name3    name3
ERJD      freshman  name1        None       None    name1
          sophomore  None       name2      name2    name2
MAM       freshman  name3        None      name1     None
PEDI      freshman   None  name1 name3      None     None
          sophomore name2        None       None     None

Я хотел бы разместить имена в таблице, например, PEDI на неделе2 имеет name1 и name3 рядом. Как я могу поместить имена в разные строки? Есть ли лучший способ сделать это вместо использования сводной таблицы? Шаг pd.melt вообще необходим?

Желаемая структура:

                    Week1       Week2      Week3    Week4
Rotation    Year                
ABD       freshman   None        None      name3    name3
ERJD      freshman  name1        None       None    name1
          sophomore  None       name2      name2    name2
MAM       freshman  name3        None      name1     None
PEDI      freshman   None        name1      None     None    
                                 name3
          sophomore name2        None       None     None

Заранее спасибо за помощь!

РЕШЕНИЕ:

После pd.melt сделайте следующее:

df['aggval'] = df['Week'].map(str) + df['Rotation']
df['aggval'] = df.groupby(['aggval']).cumcount()+1
pivot = df.pivot_table(index=['Rotation','aggval'], columns='Week', values='Name', aggfunc=lambda x: ' '.join(x)).fillna('')
pivot = pivot.reindex(weeks, axis=1)
0
Steve 20 Авг 2018 в 23:05

3 ответа

Лучший ответ

После pd.melt сделайте следующее:

df['aggval'] = df['Week'].map(str) + df['Rotation']
df['aggval'] = df.groupby(['aggval']).cumcount()+1
pivot = df.pivot_table(index=['Rotation','aggval'], columns='Week', values='Name', aggfunc=lambda x: ' '.join(x)).fillna('')
pivot = pivot.reindex(weeks, axis=1)
0
Steve 19 Сен 2018 в 17:20

Вы можете сделать это используя set_index и mul:

df1 = df.set_index(['Rotation','Year'])

df1.filter(like='Week').mul(df1['Name'], axis=0)\
  .replace('',np.nan)\
  .sort_index()

Выход:

                     Week1  Week2  Week3  Week4
Rotation Year                                 
ABD      freshman     NaN    NaN  name3  name3
ERJD     freshman   name1    NaN    NaN  name1
         sophomore    NaN  name2    NaN    NaN
         sophomore    NaN    NaN  name2  name2
MAM      freshman   name3    NaN    NaN    NaN
         freshman     NaN    NaN  name1    NaN
PEDI     freshman     NaN  name1    NaN    NaN
         freshman     NaN  name3    NaN    NaN
         sophomore  name2    NaN    NaN    NaN
0
Scott Boston 21 Авг 2018 в 20:09

Вы можете просмотреть интересующие вас недели и условно заполнить свой фрейм данных, например:

for week in ['Week1','Week2','Week3','Week4']:
    df[week] = np.where(df[week]==1, df['Name'], df[week])

Это дает:

    Name      Year Rotation  Week1  Week2  Week3  Week4
0  name1  freshman     ERJD  name1      0      0  name1
1  name2  sophmore     PEDI  name2      0      0      0
2  name3  freshman      MAM  name3      0      0      0
3  name1  freshman     PEDI      0  name1      0      0
4  name2  sophmore     ERJD      0  name2      0      0
5  name3  freshman     PEDI      0  name3      0      0
6  name1  freshman      MAM      0      0  name1      0
7  name2  sophmore     ERJD      0      0  name2  name2
8  name3  freshman      ABD      0      0  name3  name3

Затем вы можете сгруппировать ваш фрейм данных и сохранить записи строкового типа в списках:

grouped = df.drop('Name', axis=1).groupby(['Rotation','Year']).agg(lambda x: [i for i in x if type(i)==str])

Который дает:

                     Week1           Week2    Week3    Week4
Rotation Year                                               
ABD      freshman       []              []  [name3]  [name3]
ERJD     freshman  [name1]              []       []  [name1]
         sophmore       []         [name2]  [name2]  [name2]
MAM      freshman  [name3]              []  [name1]       []
PEDI     freshman       []  [name1, name3]       []       []
         sophmore  [name2]              []       []       []

Обратите внимание, что в вашем операторе есть ошибка в желаемом выводе. Нет ('MAM','sophmore') группы. Также обратите внимание, что 'sophmore' пишется 'sophomore', просто для ясности.

0
rahlf23 21 Авг 2018 в 15:07
51937806