#python-3.x #pandas #dataframe
#python-3.x #pandas #фрейм данных
Вопрос:
У меня есть фрейм данных (df1)
с такими сведениями о студенте, как —
Student ID Course Code Mark
1 C001 88
1 C002 71
2 C003 67
3 C002 92
3 C001 66
3 C004 70
4 C004 65
и другой фрейм данных (df2)
, который имеет
WR ID K ID Course Code
SP-RS-01 K001 C002, C004
SP-RS-01 K004 C002
SP-RS-02 K005
SP-RS-03 K004 C003, C004
SP-RS-03 K006 C001
Теперь мне нужен фрейм данных, который включает идентификатор KID и WR для каждого идентификатора студента в соответствии с пройденными ими курсами. И, возможно, укажите количество (как словарь), если они делали это более одного раза. Итак, что-то вроде этого, может быть —
Student ID Courses KID WR ID
1 C001, C002 K006, K001, K004 SP-RS-03
2 C003 K004 SP-RS-01, SP-RS-03
3 C001, C002, C004 K001x2, K006 SP-RS-01, SP-RS-03,
K004x2
4 C004 K004 SP-RS-01, SP-RS-03
Как мне это сделать?
Комментарии:
1. Один вопрос: должен ли идентификатор студента 3 k быть K001x2, K006, K004x2?
2.Я не слежу, у
Student ID
1
есть курсыC001, C002
, почему этоKID
простоK006
?3. Как уже упоминалось, ваш ожидаемый результат не имеет смысла. Пожалуйста, исправьте или объясните подробнее.
4. Отредактировано. Извините за путаницу.
Ответ №1:
Вы можете использовать:
#first flatten values pslitted by ,
s = (df2.set_index(['WR ID','K ID'])['Course Code']
.str.split(',s ', expand=True)
.stack()
.reset_index(level=2, drop=True)
.rename('Course Code')
)
#print (s)
#aggregate list per Course Code
df2 = (df2.drop('Course Code', axis=1)
.join(s, on=['WR ID','K ID'])
.groupby('Course Code')
.agg(list)
.reset_index()
)
print (df2)
Course Code WR ID K ID
0 C001 [SP-RS-03] [K006]
1 C002 [SP-RS-01, SP-RS-01] [K001, K004]
2 C003 [SP-RS-03] [K004]
3 C004 [SP-RS-01, SP-RS-03] [K001, K004]
from collections import Counter
#combination flattening nested lists, Counter and new format with counts
f = lambda x: ', '.join(f'{k}x{v}' if v > 1 else k
for k, v in Counter([z for y in x for z in y]).items())
#merge together and aggregate again
df = (df1.merge(df2, on='Course Code', how='left')
.groupby('Student ID')
.agg({'Course Code':', '.join,
'WR ID':f,
'K ID':f})
.reset_index()
)
print (df)
Student ID Course Code WR ID K ID
0 1 C001, C002 SP-RS-03, SP-RS-01x2 K006, K001, K004
1 2 C003 SP-RS-03 K004
2 3 C002, C001, C004 SP-RS-01x3, SP-RS-03x2 K001x2, K004x2, K006
3 4 C004 SP-RS-01, SP-RS-03 K001, K004
Редактировать:
Проблема в некоторых отсутствующих значениях, решение — преобразовать их в пустые списки:
from collections import Counter
#combination flattening nested lists, Counter and new format with counts
f = lambda x: ', '.join(f'{k}x{v}' if v > 1 else k
for k, v in Counter([z for y in x for z in y]).items())
#merge together and aggregate again
df = df1.merge(df2, on='Course Code', how='left')
df[['WR ID','K ID']] = df[['WR ID','K ID']].applymap(lambda x: x if x==x else [])
df = (df.groupby('Student ID')
.agg({'Course Code':', '.join,
'WR ID':f,
'K ID':f})
.reset_index()
)
Комментарии:
1. Привет @jezrael. Это выдает мне
'float' object not iterable
ошибку вf = lambda x ...
строке.2. @harry04 — Отредактированный ответ. Пожалуйста, проверьте это.
3. Сейчас это не выдает мне никаких ошибок, но результат сильно отличается от вашего. Я получаю только
WR ID
иK ID
для 4-й строкиStudent ID
. Все остальные пустые.4. Первая часть дает мне результирующий результат
df
, где некоторые строки дляK ID
похожи[nan, nan, K016, nan, K068]
, потому что у меня нет для них никаких значений. Во второй части приводится,df
где я получаю толькоK ID
иWR ID
значения для 4-й строки.5. Конечно, я могу отправить вам это!