Python科学计算第九章 Pandas统计分析基础 (下)

Python科学计算第九章 Pandas统计分析基础 (下) 称列索引为特征/属性每列为同质的称行索引为记录的名称数据运算与排序1. df.sort_values排序df.sort_values(排序依据索引列表, axis0, ascendingTrue)按指定的排序依据和轴向排序整行/列accending默认True为升序False为降序import pandas as pd df pd.DataFrame({col1: [A, A, B, D, C],col2: [2, 9, 8, 7, 4], col3: [1, 9, 4, 2, 3]}) print(df) col1 col2 col3 0 A 2 1 1 A 9 9 2 B 8 4 3 D 7 2 4 C 4 3 # 依据col1排序 print(df.sort_values([col1], ascendingFalse)) col1 col2 col3 3 D 7 2 4 C 4 3 2 B 8 4 0 A 2 1 1 A 9 9 2. df.rank排名df.rank(axis0, methodaverage, ascendingTrue)按轴向返回各元素的排名method处理相同值的排名时的方法average平均排名min最小排名max最大排名first出现顺序排名accending默认True为升序False为降序import pandas as pd df pd.DataFrame({col1: [A, A, B, D, C],col2: [2, 9, 8, 7, 4], col3: [1, 9, 4, 2, 3]}) print(df) col1 col2 col3 0 A 2 1 1 A 9 9 2 B 8 4 3 D 7 2 4 C 4 3 # 使用默认的methodaverage排序 print(df.rank()) col1 col2 col3 0 1.5 1.0 1.0 # 出现相同取几个排名的平均 1 1.5 5.0 5.0 2 3.0 4.0 4.0 3 5.0 3.0 2.0 4 4.0 2.0 3.0 # 使用methodmin排序 print(df.rank(methodmin)) col1 col2 col3 0 1.0 1.0 1.0 # 出现相同都取最小排名max同理都取最大(此处为2.0) 1 1.0 5.0 5.0 2 3.0 4.0 4.0 3 5.0 3.0 2.0 4 4.0 2.0 3.0 # 使用methodfirst排序 print(df.rank(methodfirst)) col1 col2 col3 0 1.0 1.0 1.0 # 出现相同升序情况下先出现的名次靠前 1 2.0 5.0 5.0 2 3.0 4.0 4.0 3 5.0 3.0 2.0 4 4.0 2.0 3.0 分位数的计算np.percentile(ser1, 百分值列表) # 返回ndarray百分值列表中数字1-100np.quantile(ser1, 分位小数列表) # 返回ndarray分位小数列表中数字0-1ser1.quantile(分位小数列表) # 返回Series分位小数列表中数字0-1若ser1.quantile只计算一个分位点则返回单个值例题1.计算[1, 3, 5, 6, 8, 9, 15, 36]的三个四分位点的值。首先排升序[1, 3, 5, 6, 8, 9, 15, 36]下标从0起 0, 1, 2, 3, 4, 5, 6, 7元素个数N80.25*(N-1)0.25*71.750.25分位a[1](a[2]-a[1])*0.753(5-3)*0.7531.54.50.5*(N-1)0.5*73.50.5分位a[3](a[4]-a[3])*0.56(8-6)*0.56170.75*(N-1)0.75*75.250.75分位a[5](a[6]-a[5])*0.259(15-9)*0.2510.5故结果数组位[4.5, 7., 10.5]import numpy as np import pandas as pd ser1 pd.Series([36, 9, 3, 5, 6, 15, 8, 1]) print(np.percentile(ser1, [25, 50, 75])) [4.5, 7., 10.5] print(np.quantile(ser1, [0.25, 0.5, 0.75])) [4.5, 7., 10.5] print(ser1.quantile([0.25, 0.5, 0.75])) 0.25 4.5 0.50 7.0 0.75 10.5 dtype:float64 2. 计算[3, 5, 7, 1, 9, 2]的25%、75%分位点。3.若已有import numpy as npimport pandas as pdser1pd.Series([8,1,4,5,9,2])则语句np.percentile(ser1,25)的执行结果应为___而语句ser1.quantile(0.7)的执行结果应为___。答案2.56.5练习题1若有9个数据15、1、8、16、13、5、9、20、3请手工计算Q1、Q2、Q3、20%、90%等分位点上的数值。然后使用percentile和quantile函数验证手工计算结果的正确性。手工计算升序[1, 3, 5, 8, 9, 13, 15, 16, 20]N90, 1, 2, 3, 4, 5, 6, 7, 80.25*(9-1)2, Q1a[2]50.5*(9-1)4, Q2a[4]90.75*(9-1)6, Q3a[6]150.2*(9-1)1.6,20%分位点a[1](a[2]-a[1])*0.63(5-3)*0.631.24.20.9*(9-1)7.290%分位点a[7](a[8]-a[7])*0.216(20-16)*0.2160.816.8import numpy as np import pandas as pd ser1 pd.Series([15, 1, 8, 16, 13, 5, 9, 20, 3]) print(np.percentile(ser1, [25, 50, 75, 20, 90])) [5., 9., 15., 4.2, 16.8] print(np.quantile(ser1, [0.25, 0.5, 0.75, 0.2, 0.9])) [5., 9., 15., 4.2, 16.8] print(ser1.quantile([0.25, 0.5, 0.75, 0.2, 0.9])) 0.25 5.0 0.50 9.0 0.75 15.0 0.20 4.2 0.90 16.8 dtype: float64 数学统计1. 描述性统计df.describedf.describe(percentilesNone, inlcudeNone, excludeNone)返回一个DataFrame包含df的描述性统计信息包括仅数值列np.number时非NaN元素个数count均值mean方差std最小值min25%分位数25%50%分位数50%75%分位数75%最大值max仅对象列np.object或O时非NaN元素个数count非重复元素个数unique出现次数最多元素toptop出现的次数freqall时包括上面两种所有信息(先对象列有的统计行再数值列)其中数值列和对象列在count这行都有数据其余在对方特有的统计行都为NaNpercentile百分位点集合默认为[0.25, 0.5, 0.75]include参与统计的列类型默认None为数值列np.number为数值列np.object或O为对象类型列all为全部列exclude排除掉的列类型import pandas as pd dict1 { name:[小A, 小B, 小C, 小C], score1:[50, 65, 65, 65], score2:[66, np.nan, 25, 25], score3:[53, np.nan, 26, np.nan] } df1 pd.DataFrame(dict1) print(df1) name score1 score2 score3 0 小A 50 66.0 53.0 1 小B 65 NaN NaN 2 小C 65 25.0 26.0 3 小C 65 25.0 NaN # 默认数值列统计 print(df1.describe()) score1 score2 score3 count 4.00 3.000000 2.000000 mean 61.25 38.666667 39.500000 std 7.50 23.671361 19.091883 min 50.00 25.000000 26.000000 25% 61.25 25.000000 32.750000 50% 65.00 25.000000 39.500000 75% 65.00 45.500000 46.250000 max 65.00 66.000000 53.000000 # 统计对象列 print(df1.describe(includeO)) name count 4 unique 3 top 小C freq 2 # 统计全部列 print(df1.describe(includeall)) name score1 score2 score3 count 4 4.00 3.000000 2.000000 unique 3 NaN NaN NaN top 小C NaN NaN NaN freq 2 NaN NaN NaN mean NaN 61.25 38.666667 39.500000 std NaN 7.50 23.671361 19.091883 min NaN 50.00 25.000000 26.000000 25% NaN 61.25 25.000000 32.750000 50% NaN 65.00 25.000000 39.500000 75% NaN 65.00 45.500000 46.250000 max NaN 65.00 66.000000 53.000000 2. 求和df.sumdf.sum(axisNone, skipnaTrue, numeric_onlyNone)返回一个Series索引为df的列名值为字符串列的字符串连接结果或数值列求和的值skipna跳过缺失值默认为Truenumeric_only仅计算数值列默认为Noneimport pandas as pd dict1 { name:[小A, 小B, 小C, 小C], score1:[50, 65, 65, 65], score2:[66, np.nan, 25, 25], score3:[53, np.nan, 26, np.nan] } df1 pd.DataFrame(dict1) print(df1) name score1 score2 score3 0 小A 50 66.0 53.0 1 小B 65 NaN NaN 2 小C 65 25.0 26.0 3 小C 65 25.0 NaN print(df1.sum()) name 小A小B小C小C # 字符串连接 score1 245 # 数值列求和 score2 116.0 score3 79.0 dtype: object 数据分组df.groupbydf.groupby(分组依据)1. 按列标签、列标签组合分组gp1 df.groupby(列标签) # 按列标签分组该列数据相同的分到同一组gp2 df.groupby(列标签列表) # 按列标签组合分组列组合数据相同的分到同一组gp1.groups # 查看分组情况(查看groups属性)import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 按列标签分组 gp1 df1.groupby(n1) print(gp1.groups) {22: [1], 25: [2], 50: [0, 3, 4]} # 按列标签组合分组 gp2 df1.groupby([s1, s2]) # [s1, s2]相同的分为一组 print(gp2.groups) {(a, a): RangeIndex(start2, stop3, step1), (a, b): RangeIndex(start0, stop1, step1), (b, a): Index([1, 3, 4], dtypeint64)} 2. 按字典映射分组import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 按字典映射分组 mapping {0:X, 1:Y, 2:X, 3:Y, 4:X} # 索引0,2,4分到X组索引1,3分到Y组 gp1 df1.groupby(mapping) print(gp1.groups) {X: [0, 2, 4], Y: [1, 3]} 3. 按序列分组序列与行数(axis0)/列数(axis1)长度相同import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 按序列分组 lst [5, 7, 6, 7, 5] gp1 df1.groupby(lst) # 第0、4行分到5组1、3行分到7组2行分到6组 print(gp1.groups) {5: [0, 4], 6: [2], 7: [1, 3]} 4. 按行索引作用函数后结果分组import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 行索引作用函数后的值 gp1 df1.groupby(lambda x: x1 if x2 else x**2) print(gp1.groups) {0: [0], 1: [1], 4: [2, 3], 5: [4]} 5. 按分组统计在分组上可作用sum(), mean(), count(), size()等统计函数注意区分只有groupby对象可以用size函数df仅可用df.size返回属性agg1.count()统计agg1分组中每组中每列上有几个非NaN元素agg1.size()统计agg1分组中每组中有几个组员import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 按序列分组 lst [5, 7, 6, 7, 5] gp1 df1.groupby(lst) # 第0、4行分到5组1、3行分到7组2行分到6组 print(gp1.groups) {5: [0, 4], 6: [2], 7: [1, 3]} print(gp1.count()) n1 n2 s1 s2 5 2 2 2 2 6 1 1 1 1 7 2 2 2 2 print(gp1.size()) 5 2 6 1 7 2 dtype: int64 print(gp1[n1].mean()) 5 50.0 6 25.0 7 36.0 Name: n1, dtype: float64 print(gp1[n2].sum()) 5 100 6 65 7 130 Name: n2, dtype: int64 数据聚合df.agg1. 所有行列通过同一函数列表聚合df.agg(函数列表, axis0) # 通过函数在指定轴上完成聚合操作默认处理全部行/列若numeric_only设True则自动跳过非数值行/列import pandas as pd import numpy as np dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50] } df1 pd.DataFrame(dict1) print(df1) n1 n2 0 50 50 1 22 65 2 25 65 3 50 65 4 50 50 # 进行聚合带引号的表示DataFrame的函数不带的表示通用函数或np的函数 print(df1.agg([sum, min, sum, np.min])) n1 n2 sum 197 295 min 22 50 sum 197 295 min 22 50 2. 在不同行列上通过不同函数聚合使用键值对为列名:函数列表的字典来指定import pandas as pd import numpy as np dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50] } df1 pd.DataFrame(dict1) print(df1) n1 n2 0 50 50 1 22 65 2 25 65 3 50 65 4 50 50 # n1上sum、minn2上mean print(df1.agg({n1:[sum, min], n2:[mean]})) n1 n2 # 未做该函数的该位置标NaN sum 197.0 NaN min 22.0 NaN mean NaN 59.0 3. 在groupby对象上使用agg被作为分组键的列不参与后续聚合操作gp1.agg(函数字典或列表, axis0)import pandas as pd dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 按列标签分组 gp1 df1.groupby(n1) print(gp1.groups) {22: [1], 25: [2], 50: [0, 3, 4]} # 对分组进行聚合操作 print(gp1.agg([sum, count])) n2 s1 s2 # n1作为分组键不参与运算。出现多级列索引 sum count sum count sum count n1 22 65 1 b 1 a 1 25 65 1 a 1 a 1 50 165 3 abb 3 baa 3 4. 数据聚合gp.applyimport pandas as pd import numpy as np dict1 { n1:[50, 22, 25, 50, 50], n2:[50, 65, 65, 65, 50], s1:[a, b, a, b, b], s2:[b, a, a, a, a], } df1 pd.DataFrame(dict1) print(df1) n1 n2 s1 s2 0 50 50 a b 1 22 65 b a 2 25 65 a a 3 50 65 b a 4 50 50 b a # 行索引作用函数后的值 gp1 df1.groupby(lambda x: x1 if x2 else x**2) print(gp1.groups) {0: [0], 1: [1], 4: [2, 3], 5: [4]} # 使用apply对分组应用函数进行聚合 print(gp1[[n1, n2]].apply(np.sum)) # 使用np.sum np.sum→全局总和(展平后求和)→一维Series 0 100 1 87 4 205 5 100 dtype: int64 print(gp1[[n1, n2]].apply(lambda x: x.sum())) # 使用lambda表达式 df.sum()→逐列总和→二维DataFrame n1 n2 0 50 50 1 22 65 4 75 130 5 50 50 Pandas读写数据1. 读写csv文件(1) 写入df.to_csvdf.to_csv(文件路径字符串, sep,, columnsNone, headerTrue, indexTrue)文件路径字符串如同目录下文件./Scores.csvsep分隔符默认为逗号columns需要写入的列header是否写入列名默认为Trueindex是否写入行索引默认为True(2) 读取pd.read_csvdf pd.read_csv(文件路径字符串, sep,, header0, namesNone)header指定第几行为列名并舍弃该行之前的数据。默认第一行(header0)。若保存时未保存列名第一行就是数据那么可以指定headerNone不指定列名names重命名列名可指定新的列名列表import pandas as pd dict1 { name:[小A, 小B, 小C, 小C], score1:[50, 65, 65, 65], score2:[66, np.nan, 25, 25], score3:[53, np.nan, 26, np.nan] } df1 pd.DataFrame(dict1) print(df1) name score1 score2 score3 0 小A 50 66.0 53.0 1 小B 65 NaN NaN 2 小C 65 25.0 26.0 3 小C 65 25.0 NaN # 只保存分数列保存行索引不保存列名 df1.to_csv(./Score.csv, columns[score1, score2, score3], headerFalse) # 不选择列名行指定新列名读取 df2 pd.read_csv(./Score.csv, sep,, headerNone, names[分数1, 分数2, 分数3]) print(df2) 分数1 分数2 分数3 0 50 66.0 53.0 1 65 NaN NaN 2 65 25.0 26.0 3 65 25.0 NaN 读写excel文件(1) 写入df.to_exceldf.to_excel(文件路径字符串, sheet_namesheet1, columnsNone, headerTrue, indexTrue)sheet_name默认写入在sheet1工作表可指定到其它表columns需要写入的列header是否写入列名默认为Trueindex是否写入行索引默认为True(2) 读取pd.read_exceldf pd.read_excel(文件路径字符串, sheet_name0, header0, index_colNone, namesNone)header指定第几行为列名并舍弃该行之前的数据。默认第一行(header0)。若保存时未保存列名第一行就是数据那么可以指定headerNone不指定列名sheet_name默认0读取第一张表设为None读取全部表可传入列表读取多个表index_col指定某列为行索引names重命名列名可指定新的列名列表import pandas as pd dict1 { name:[小A, 小B, 小C, 小C], score1:[50, 65, 65, 65], score2:[66, np.nan, 25, 25], score3:[53, np.nan, 26, np.nan] } df1 pd.DataFrame(dict1) print(df1) name score1 score2 score3 0 小A 50 66.0 53.0 1 小B 65 NaN NaN 2 小C 65 25.0 26.0 3 小C 65 25.0 NaN # 保存行列索引 df1.to_excel(./score.xlsx) # 直接读取不指定行列索引 df2 pd.read_excel(./score.xlsx) print(df2) Unnamed: 0 name score1 score2 score3 # 原行索引被作为一列数据读出下一段代码解决该问题 0 0 小A 50 66.0 53.0 1 1 小B 65 NaN NaN 2 2 小C 65 25.0 26.0 3 3 小C 65 25.0 NaN # 指定第0列为行索引读取的几列重命名列索引 df3 pd.read_excel(./score.xlsx, index_col0, names[姓名, 分数1, 分数2, 分数3]) print(df3) 姓名 分数1 分数2 分数3 0 小A 50 66.0 53.0 1 小B 65 NaN NaN 2 小C 65 25.0 26.0 3 小C 65 25.0 NaN 练习题2从“国民经济核算季度数据.npz”文件中读取2000年第一季度到2017年第一季度的所有数据并存储在ndarray对象中。(1) 创建一个DataFrame对象其数值数组不包含原ndarray对象的第0列和最后一行数据即不包含“序号”那一列数据和“2017年第一季度”那一行数据其列索引为[时间, GDP, 一产, 二产, 三产, 农业, 工业, 建筑, 批发, 交通, 餐饮, 金融, 房地产, 其他](2) 按“年份”分组需提取“时间”那一列数据中包含的“年份”信息提出来按一个列表。在此基础上计算每年总的GDP三个产业以及各行业的全年GDP“年份”的跨度为20002016年。(3) 在每个年份上计算三个产业的全年GDP之和以及各行业的全年GDP之和并分别以“产业GDP之和”和“行业GDP之和”为列索引名将计算结果添加到对应的DataFrame对象中。(4) 在每个年份上分别计算“产业GDP之和”之于年“GDP”年“GDP”就是第(2)小题所说的每年总的GDP也就是每年4个季度的GDP之和以及“行业GDP之和”之于年“GDP”的相对误差计算公式为以“产业……”为例(“产业GDP之和”-“GDP”)/“GDP”然后分别以“产业之和的误差”和“行业之和的误差”为列索引名将计算结果添加到对应的DataFrame对象中(5) 抽取并输出“GDP”“产业GDP之和”“产业之和的误差”“行业GDP之和”“行业之和的误差”这几列数据其部分显示结果如下所示GDP 产业GDP之和 产业之和的误差 行业GDP之和 行业之和的误差2000 100280.1 100280.0 -9.972068e-07 100280.0 -9.972068e-072001 110863.1 110863.1 0.000000e00 110863.1 0.000000e002002 121717.4 121717.4 -1.195549e-16 121717.5 8.215752e-07…… …… …… …… …… ……2015 689052.0 689052.2 2.902539e-07 689051.9 -1.451269e-072016 744127.2 744127.3 1.343856e-07 744127.2 0.000000e00代码检验是不是所有误差都在万分之一以内并以此来判定“国民经济核算季度数据.npz”文件中的数据是不是“有效”的(6) 如果数据是有效的将第(2)小题分组计算所得的DataFrame对象的行索引命名为“年份”。然后再将该数据包括行索引和列索引存储在“GDP年度数据.csv”文件中。# 本人思路仅供参考 import numpy as np import pandas as pd arr1 np.load(./国民经济核算季度数据.npz, allow_pickleTrue) columns1 arr1[columns] data arr1[values] print(columns1) print(data) # (1) columns2 [时间, GDP, 一产, 二产, 三产, 农业, 工业, 建筑, 批发, 交通, 餐饮, 金融, 房地产, 其他] df pd.DataFrame(data[:-1, 1:], columnscolumns2) print((1)) print(df) # (2) lst [item[0:4] for item in df[时间]] print((2)) print(分组列表为) print(lst) gp1 df.groupby(lst) print(根据分组列表分组如下) print(gp1.groups) df_year gp1.agg(sum).drop(columns时间) print(年数据df如下) print(df_year) # (3) df2 df_year.copy() df2[产业GDP之和] df2[[一产, 二产, 三产]].sum(axis1) df2[行业GDP之和] df2.loc[:, 农业:其他].sum(axis1) # 注意这里必须是[:, 农业:其他]而不能是[:, 农业:]后者会将刚刚添加的产业GDP之和列也计算进去 print((3)) print(df2) # (4) def div(ser1, ser2): ser_r (ser1 - ser2) / ser2 return ser_r df2[产业之和的误差] div(df2[产业GDP之和], df2[GDP]) df2[行业之和的误差] div(df2[行业GDP之和], df2[GDP]) print((4)) print(df2) # (5) usable False print((5)) print(抽取数据如下) print(df2[[GDP, 产业GDP之和, 产业之和的误差, 行业GDP之和, 行业之和的误差]]) if all(df2[产业之和的误差].abs() 0.0001) and all(df2[行业之和的误差].abs() 0.0001): print(数据有效) usable True else: print(数据无效) # (6) print((6)) if usable: df_year.index.name 年份 df_year.to_csv(./GDP年度数据.csv, indexTrue, headerTrue) print(数据已保存到./GDP年度数据.csv中) else: print(数据无效未保存)练习题3“mtcars.csv”文件中存储了某些汽车型号的特征数据包括name(汽车型号)cyl(汽缸数)carb(化油器)mpg(油耗)hp(马力)等特征。(1) 使用pandas读取mtcars数据集输出数据集的大小shape(2) 抽取并输出5个数值型特征的描述性统计信息自行解释这些数据的含义(3) 按cyl和carb进行分组计算并输出hp列每个分组所包含的有效数据的个数、每个分组的最大马力、每个分组的最小马力以及mpg列每个分组所包含的有效数据的个数、每个分组的平均油耗。# 本人思路仅供参考 import pandas as pd # (1) df pd.read_csv(./mtcars.csv) print((1)) print(原数据集为) print(df) print(原数据集大小为) print(df.shape) # (2) print((2)) print(df[[cyl, carb, mpg, hp, qsec]].describe()) # (3) gp df.groupby([cyl, carb]) print((3)) print(分组结果为) print(gp.agg({hp:[count, max, min], mpg:[count, mean]}))练习题4“Scores.xlsx”文件中存储了计算机专业2020级全部同学分属3个不同的班在2021学年秋季学期3门公共课的考试成绩包括学号、姓名、班号、3门公共课的成绩为了简单起见分别用C1C2C3表示等信息。由于疫情原因有一部分同学没有参加某些课程的期末考试对应成绩用NaN表示。其列表化的部分数据如下所示学号 姓名 班号 C1 C2 C32020003 李珏 202001 76.0 88.0 67.0…… …… …… …… ……2020038 吴琼 202002 74.0 96.0 92.52020039 颜敏 202002 88.0 NaN 73.0…… …… …… …… ……2020072 钱思思 202003 55.0 97.0 54.0…… …… …… …… ……(1) 使用pandas读取“Scores.xlsx”文件构造原始DataFrame对象(2) 删除所有成绩中含为NaN的学生信息不作为有效信息计入最终的统计并重置行索引(3) 在(2)的基础上计算每个同学3门课程成绩的平均分并将其作为新的一列列索引为aver添加到(2)的结果中。(4) 在(3)的基础上计算并输出每个班参与统计的同学总数每个班的最高平均成绩每个班的最低平均成绩每个班平均成绩的均值。# 本人思路仅供参考 import numpy as np import pandas as pd # (1) df pd.read_excel(Scores.xlsx) print((1)) print(原df为) print(df) # (2) df.dropna(howany, ignore_indexTrue, inplaceTrue) print((2)) print(df) # (3) df[aver] df.loc[:, C1:C3].mean(axis1) print((3)) print(df) # (4) gp df.groupby(班号) print(gp[aver].agg([count, max, min, mean]))