如何将列内容解压缩为由单元格值确定的新列

时间:2019-05-15 21:05:50

标签: python pandas

我有一个数据框,其中包含有关学生成绩,考试成绩和其他指标的信息。列之一包含逗号分隔的文本,其中每个逗号分隔的值是数学课程的名称和学生在该课程中取得的成绩。因此,数据框如下所示:

STUDENT_ID    TEST_SCORE_1    TEST_SCORE_2    MATHS
001           85              93              ALGEBRA_B+,GEOMETRY_A-,TRIGONOMETRY_C
002           73              95              ALGEBRA_B,GEOMETRY_B+,CALCULUS_C

我想要的是拥有与每个班级相对应的列,并简单地将包含这样的成绩的单元格放进去:

STUDENT_ID    TEST_SCORE_1    TEST_SCORE_2    ALGEBRA    GEOMETRY    TRIGONOMETRY    CALCULUS
001           85              93              B+         A-          C               NaN
002           73              95              B          B+          NaN             C

我首先尝试做这样的事情

df.merge(df['Maths'].apply(unpack_grades), left_index=True, right_index=True)

其中,unpack_grades是一个函数,该函数解析类和年级的字符串,并返回一个熊猫系列,其中包含目录中的每个数学课程作为键,并以年级作为值(如果学生未上课,则为NaN)。这是该功能的开头:

def unpack_grades(x):

    courses = [a.strip() for a in x.split(',')]

但是,出现以下错误:

AttributeError: 'float' object has no attribute 'split'

如果有人可以为我的错误提出修复建议,或者如果有更直接的方法来实现我所追求的目标,甚至可以采用其他方法,那就太好了。

1 个答案:

答案 0 :(得分:2)

您可以在此处使用正则表达式和pivot

u = df.MATHS.str.extractall(r'([a-zA-Z]+)_([A-F][+-]?)').reset_index(1, drop=True)

#               0   1
# 0       ALGEBRA  B+
# 0      GEOMETRY  A-
# 0  TRIGONOMETRY   C
# 1       ALGEBRA   B
# 1      GEOMETRY  B+
# 1      CALCULUS   C

p = u.pivot(columns=0, values=1)

# 0 ALGEBRA CALCULUS GEOMETRY TRIGONOMETRY
# 0      B+      NaN       A-            C
# 1       B        C       B+          NaN

pd.concat([df.iloc[:, :-1], p], axis=1)

   STUDENT_ID  TEST_SCORE_1  TEST_SCORE_2 ALGEBRA CALCULUS GEOMETRY TRIGONOMETRY
0           1            85            93      B+      NaN       A-            C
1           2            73            95       B        C       B+          NaN

正则表达式说明

(                            # capture group 1
  [a-zA-Z]                   # match letters
  +                          # match 1 or more times
)
_                            # match the _ character
(                            # capture group 2
  [A-F]                      # match A-F (possible grades)
  [+-]                       # match either + or -
  ?                          # optional match of the + or -
)