Разбить строку фрейма данных pandas, содержащую словарь, на несколько строк

#python #pandas #dictionary

#python #pandas #словарь

Вопрос:

У меня есть фрейм данных pandas с двумя столбцами — group_id и personal_score. Столбец идентификатора группы содержит некоторые идентификационные номера, где столбец личных оценок содержит словари разной длины. Вот пример:

   group_id personal_score
0  77     {'149': 17, '819': 22}
1  37     {'821': 18, '359': 24, '089': 17, '170': 15}
2  51     {'280': 18, '261': 18, '628': 20, '722': 21, '744': 19, '152': 19}
3  84     {'140': 19}
 

Я хочу разделить словари в столбце personal_score на два столбца: personal_id, который принимает ключ словаря, и score, который принимает значение, в то время как значение в столбце group_id повторяется для всех разделенных строк из соответствующего словаря. Вывод должен выглядеть следующим образом:

   group_id     personal_id     score
0   77              149            17
1   77              819            22
2   37              821            18
3   37              359            24
4   37              089            17
5   37              170            15
6   51              280            18
7   51              261            18
8   51              628            20
9   51              722            21
10  51              744            19
11  51              152            19
12  84              140            19
 

Ваша помощь очень ценится.

Ответ №1:

Вы могли бы сделать:

 df = pd.DataFrame([[i, k, v] for i, d in df[['group_id', 'personal_score']].values for k, v in d.items()],
                  columns=['group_id', 'personal_id', 'score'])
print(df)
 

Вывод

     group_id personal_id  score
0         77         149     17
1         77         819     22
2         37         821     18
3         37         359     24
4         37         089     17
5         37         170     15
6         51         280     18
7         51         261     18
8         51         628     20
9         51         722     21
10        51         744     19
11        51         152     19
12        84         140     19
 

Ответ №2:

Вы можете сделать это с помощью:

 data={  "group_id":[77,37,51,84],
        "personal_score":[{'149': 17, '819': 22},{'821': 18, '359': 24, '089': 17, '170': 15},
                        {'280': 18, '261': 18, '628': 20, '722': 21, '744': 19, '152': 19},
                        {'140': 19}]}

df=pd.DataFrame(data)
perso_score = pd.DataFrame(pd.DataFrame(df['personal_score'].values.tolist()).stack().reset_index(level=1))
perso_score.columns = ['personal_ID','score']
df.drop(columns='personal_score',inplace=True)
df = df.join(perso_score )

print(df)
 

Результат:

    group_id personal_ID  score
0        77         149   17.0
0        77         819   22.0
1        37         821   18.0
1        37         359   24.0
1        37         089   17.0
1        37         170   15.0
2        51         280   18.0
2        51         261   18.0
2        51         628   20.0
2        51         722   21.0
2        51         744   19.0
2        51         152   19.0
3        84         140   19.0
 

Ответ №3:

Давайте будем ленивы и попробуем:

 # this creates a lot of unnecessary NaN in the data
# and we use `stack` to kill them
# that's why we say `lazy`
(pd.DataFrame(df.set_index('group_id')['personal_score'].to_dict())
   .stack()
   .rename_axis(index=('personal_id','group_id'))
   .reset_index(name='score')
)
 

Другой способ — выполнить понимание и объединение dict:

 (pd.concat({x:pd.DataFrame({'score':y}) 
           for x,y in zip(df['group_id'], df['personal_score'])
          })
   .rename_axis(['personal_id','group_id'])
   .reset_index()
)
 

Вывод:

    personal_id  group_id  score
0          149        77   17.0
1          819        77   22.0
2          821        37   18.0
3          359        37   24.0
4          089        37   17.0
5          170        37   15.0
6          280        51   18.0
7          261        51   18.0
8          628        51   20.0
9          722        51   21.0
10         744        51   19.0
11         152        51   19.0
12         140        84   19.0