多级索引(也称层次化索引)是pandas的重要功能,可以在Series、DataFrame对象上拥有2个以及2个以上的索引。
实质上,单级索引对应Index对象,多级索引对应MultiIndex对象。

一、Series对象的多级索引

  • 多级索引Series对象的创建
  • import pandas as pd
    import numpy as np
    se1=pd.Series(np.random.randn(4),index=[list("aabb"),[1,2,1,2]])
    Out[6]: 
    a  1    0.357171
       2    0.084055
    b  1   -0.678752
       2    0.132007
    dtype: float64
    • 子集的选取
    • se1['a']
      Out[7]: 
      1    0.357171
      2    0.084055
      dtype: float64
      se1['a':'b']
      Out[8]: 
      a  1    0.357171
         2    0.084055
      b  1   -0.678752
         2    0.132007
      dtype: float64 
      se1[:, 1]
      Out[9]: 
      a    0.357171
      b   -0.678752
      dtype: float64
      se1[:, 2]
      Out[10]: 
      a    0.084055
      b    0.132007
      dtype: float64

      二、DataFrame对象的多级索引

      • 1. 创建多层行索引
      • import numpy as np
        df = pd.DataFrame(np.random.randint(0, 150, size=(6,3)), columns=['语文', '数学', 'Python'], index=[['Michal', 'Michal', 'Kobe','Kobe', 'James', 'James'],['Mid','End', 'Mid', 'End','Mid', 'End']])
        Out[25]: 
                     语文   数学  Python
        Michal Mid  100   43      73
               End   11   18      60
        Kobe   Mid  104   66      54
               End   30  120     134
        James  Mid  135   77      56
               End   45  127      63
        df = pd.DataFrame(np.random.randint(0, 150, size=(6,3)), columns=['语文', '数学', 'Python'], index=pd.MultiIndex.from_arrays([['Michal', 'Michal', 'Kobe','Kobe', 'James', 'James'],['Mid','End', 'Mid', 'End','Mid', 'End']]))
        Out[27]: 
                    语文   数学  Python
        Michal Mid  56   46     104
               End  83   57      95
        Kobe   Mid  48   94      45
               End  22   99      49
        James  Mid  65   66      91
               End  69  101      84  
        df = pd.DataFrame(np.random.randint(0, 150, size=(6,3)), columns=['语文', '数学', 'Python'], index=pd.MultiIndex.from_tuples([('Michal','期中'), ('Michal','期末'), ('Kobe','期中'), ('Kobe','期末'), ('James','期中'), ('James','期末')]))
        Out[29]: 
                    语文   数学  Python
        Michal 期中   10  107      48
               期末  113   49     147
        Kobe   期中  116  138      29
               期末    7   64      53
        James  期中    1   30      21
               期末   70   76     108
        • 使用product
        • df = pd.DataFrame(np.random.randint(0, 150, size=(6,3)), columns=['语文', '数学', 'Python'], index=pd.MultiIndex.from_product([['Michal','Kobe','James'],['Mid','End']]))
          Out[31]: 
                      语文   数学  Python
          Michal Mid  85   89      17
                 End  21    4      23
          Kobe   Mid  54  117     108
                 End  37   20      79
          James  Mid  56   47      82
                 End  45   57     126

          2. 多层列索引

          df = pd.DataFrame(np.random.randint(0, 150, size=(3,6)), index=['语文', '数学', 'Python'], columns=pd.MultiIndex.from_product([['Michal','Kobe','James'],['Mid','End']]))
          Out[34]: 
                 Michal     Kobe      James     
                    Mid End  Mid  End   Mid  End
          语文         74  84   76  142    36   87
          数学         44  90   57  143    78   68
          Python     79  46  120   47   128  145
          

              3. 索引赋值,设置名称和交换

          df1=pd.DataFrame(np.arange(12).reshape(4,3),index=[list("AABB"),[1,2,1,2]],columns=[list("XXY"),[10,11,10]])
          Out[11]: 
               X       Y
              10  11  10
          A 1  0   1   2
            2  3   4   5
          B 1  6   7   8
            2  9  10  11
          df1.columns.names=['XY','sum']
          df1.index.names=['AB','num']
          Out[12]: 
          XY      X       Y
          sum    10  11  10
          AB num           
          A  1    0   1   2
             2    3   4   5
          B  1    6   7   8
             2    9  10  11
          • 创建MultiIndex对象再作为索引
          • df1.index=pd.MultiIndex.from_arrays([list("AABB"),[3,4,3,4]],names=["AB","num"])
            Out[13]: 
            XY      X       Y
            sum    10  11  10
            AB num           
            A  3    0   1   2
               4    3   4   5
            B  3    6   7   8
               4    9  10  11
            • 可以对各级索引进行互换
            • df1.swaplevel('AB','num')
              Out[14]: 
              XY      X       Y
              sum    10  11  10
              num AB           
              3   A   0   1   2
              4   A   3   4   5
              3   B   6   7   8
              4   B   9  10  11

                  4. 获取索引值

              df = pd.DataFrame(np.random.randint(0, 150, size=(6,3)), columns=['语文', '数学', 'Python'], index=pd.MultiIndex.from_product([['Michal','Kobe','James'],['Mid','End']]))
              Out[38]: 
                           语文   数学  Python
              Michal Mid   65  134      85
                     End   94   91      48
              Kobe   Mid  118  142     141
                     End    2   32     106
              James  Mid   29   11     127
                     End   16   93      99
              df.index
              Out[39]: 
              MultiIndex([('Michal', 'Mid'),
                          ('Michal', 'End'),
                          (  'Kobe', 'Mid'),
                          (  'Kobe', 'End'),
                          ( 'James', 'Mid'),
                          ( 'James', 'End')],
              # loc获取
              df.loc['James', :]
              Out[42]: 
                   语文  数学  Python
              Mid  29  11     127
              End  16  93      99
              df[df.index.get_level_values(0) == 'Michal']
              Out[45]: 
                          语文   数学  Python
              Michal Mid  65  134      85
                     End  94   91      48
              df[df.index.get_level_values(1) == 'Mid']
              Out[46]: 
                           语文   数学  Python
              Michal Mid   65  134      85
              Kobe   Mid  118  142     141
              James  Mid   29   11     127
              df.loc[('James', 'Mid'), :]
              Out[41]: 
              语文         29
              数学         11
              Python    127
              Name: (James, Mid), dtype: int32

               三、案例:考试数据分析

              1. 计算每个学生的总成绩

              2. 计算每个学生各学期的总成绩

              3. 各门课程平均成绩

              4. 各学期大于本课程平均成绩的学生姓名及成绩

              import pandas as pd
              exam_data = pd.read_excel('试题.xlsx', sheet_name='试题数据')
              exam_data
              Out[3]: 
                   姓名    课程  学期  成绩
              0   王大伟  大学英语   1  92
              1   王大伟  大学英语   2  85
              2   王大伟  大学英语   3  83
              3   王大伟  大学英语   4  90
              4   王大伟  高等数学   1  91
              5   王大伟  高等数学   2  86
              6   王大伟  高等数学   3  98
              7   王大伟  高等数学   4  84
              8   王大伟  大学体育   1  78
              9   王大伟  大学体育   2  91
              
              # 读取时设置
              exam_data = pd.read_excel('试题.xlsx', sheet_name='试题数据', index_col=[0, 1])
              exam_data
              Out[5]: 
                        学期  成绩
              姓名  课程          
              王大伟 大学英语   1  92
                  大学英语   2  85
                  大学英语   3  83
                  大学英语   4  90
                  高等数学   1  91
                  高等数学   2  86
                  高等数学   3  98
                  高等数学   4  84
                  大学体育   1  78
                  大学体育   2  91
                  大学体育   3  80
                  大学体育   4  90
              孙力  大学英语   1  87
                  大学英语   2  79
                  大学英语   3  93
                  大学英语   4  78
                  高等数学   1  87
                  高等数学   2  93
                  高等数学   3  85
                  高等数学   4  89
                  大学体育   1  77
                  大学体育   2  83
                  大学体育   3  99
                  大学体育   4  88
              张明  大学英语   1  88
                  大学英语   2  94
                  大学英语   3  96
                  大学英语   4  87
                  高等数学   1  97
                  高等数学   2  89
                  高等数学   3  94
                  高等数学   4  86
                  大学体育   1  87
                  大学体育   2  85
                  大学体育   3  86
                  大学体育   4  92
              # 设置索引列
              exam_data.set_index(keys=['姓名', '课程'])
              Out[21]: 
                        学期  成绩
              姓名  课程          
              王大伟 大学英语   1  92
                  大学英语   2  85
                  大学英语   3  83
                  大学英语   4  90
                  高等数学   1  91
                  高等数学   2  86
                  高等数学   3  98
                  高等数学   4  84
                  大学体育   1  78
                  大学体育   2  91
                  大学体育   3  80
                  大学体育   4  90
              孙力  大学英语   1  87
                  大学英语   2  79
                  大学英语   3  93
                  大学英语   4  78
                  高等数学   1  87
                  高等数学   2  93
                  高等数学   3  85
                  高等数学   4  89
                  大学体育   1  77
                  大学体育   2  83
                  大学体育   3  99
                  大学体育   4  88
              张明  大学英语   1  88
                  大学英语   2  94
                  大学英语   3  96
                  大学英语   4  87
                  高等数学   1  97
                  高等数学   2  89
                  高等数学   3  94
                  高等数学   4  86
                  大学体育   1  87
                  大学体育   2  85
                  大学体育   3  86
                  大学体育   4  92

              当然,这里我们不需要对其设置索引

              • 1. 计算每个学生总成绩
              • exam_data = pd.read_excel('试题.xlsx', sheet_name='试题数据')
                # 1. 计算每个学生总成绩
                student_total_score = exam_data.groupby(by=['姓名']).agg(
                    {'成绩': sum}).rename(columns={'成绩': '总成绩'})
                print('1. 学生总成绩:\n', student_total_score)
                1. 学生总成绩:
                孙力   1038
                张明   1081
                王大伟  1048
                
                • 2. 每个学生各学期的总成绩
                • # 2. 每个学生各学期的总成绩
                  student_semester_total = exam_data.groupby(by=['姓名', '学期']).agg(
                      {'成绩': sum}).rename({'成绩': ' 总成绩'})
                  print('\n2. 学生每个学期总成绩:\n', student_semester_total)
                  2. 学生每个学期总成绩:
                  姓名  学期     
                  孙力  1   251
                      2   255
                      3   277
                      4   255
                  张明  1   272
                      2   268
                      3   276
                      4   265
                  王大伟 1   261
                      2   262
                      3   261
                      4   264
                  

                    3. 各门课程平均成绩

                  # 3. 各门课程平均成绩
                  course_avg_score = exam_data.groupby(by=['课程'])['成绩'].mean()
                  print('\n3. 各门课程平均成绩:\n', course_avg_score)
                  3. 各门课程平均成绩:
                  大学体育    86.333333
                  大学英语    87.666667
                  高等数学    89.916667
                  Name: 成绩, dtype: float64
                  
                  • 4. 各学期大于本课程平均成绩的学生姓名及成绩
                  • def judge_score(row):
                        return row['成绩'] > course_avg_score[row['课程']]
                    greater_than_avg_student = exam_data[exam_data.apply(judge_score, axis=1)].set_index(keys=['姓名', '课程'])
                    print('\n4. 各学期大于本课程平均成绩的学生姓名及成绩: \n', greater_than_avg_student)
                    4. 各学期大于本课程平均成绩的学生姓名及成绩: 
                               学期  成绩
                    姓名  课程          
                    王大伟 大学英语   1  92
                        大学英语   4  90
                        高等数学   1  91
                        高等数学   3  98
                        大学体育   2  91
                        大学体育   4  90
                    孙力  大学英语   3  93
                        高等数学   2  93
                        大学体育   3  99
                        大学体育   4  88
                    张明  大学英语   1  88
                        大学英语   2  94
                        大学英语   3  96
                        高等数学   1  97
                        高等数学   3  94
                        大学体育   1  87
                        大学体育   4  92
                    •  将结果输出到文件
                    • # 输出文件
                      with pd.ExcelWriter(path="结果.xlsx") as writer:
                          exam_data.to_excel(excel_writer=writer, sheet_name='试题数据', encoding='utf-8', index=False)
                          student_total_score.to_excel(excel_writer=writer, sheet_name='学生总成绩', encoding='utf-8')
                          student_semester_total.to_excel(excel_writer=writer, sheet_name='每个学生各学期总成绩', encoding='utf-8')
                          course_avg_score.to_excel(excel_writer=writer, sheet_name='各门课程平均成绩', encoding='utf-8')
                          greater_than_avg_student.to_excel(excel_writer=writer, sheet_name='各学期大于本课程平均成绩的学生姓名及成绩', encoding='utf-8')
                          writer.save()
                                                  
                      HTML5 输入y继续输入数字 html数字输入框

                      2、表单元素-输入框输入框使用input标签。<input>标签,根据type属性的不同,会有不同的表现样式。默认type="text",也就是文本输入框。2.1、文本输入框单行的文本区域,(输入中的换行会被自动去除)。<input type="text" name="username" maxlength="6" readonly="readonly"