Pandas系列(十八)- 多級索引


多級索引

多級索引(也稱層次化索引)是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]])
se1
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']])
df
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']]))
df
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','期末')]))
df
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']]))
df
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']]))
df
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]])
df1
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']
df1
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"])
df1
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']]))
df
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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM