数据分析案例(二):学生成绩数据的预处理、探索性分析和可视化

实验1  学生成绩数据的预处理、探索性分析和可视化

1. 有60名学生的两门课程成绩的数据文件(文件名分别为ReportCard1和ReporCard2),分别记录着学生的学号、性别以及不同课程的成绩。请将数据读入Pandas数据框,并做如下处理:

1)将两个数据文件按学号合并为一个数据文件,得到包含所有课程成绩的数据文件。

2)计算每个同学的各门课程的总成绩和平均成绩。

3)将数据按总成绩的降序排序。

4)按性别分别计算各门课程的平均成绩。

5)按优、良、中、及格和不及格,对平均成绩进行分组。

6)按性别统计优、良、中、及格和不及格的人数。

7)生成性别的虚拟自变量。

8)绘制总成绩的直方图。

9)绘制平均成绩的优、良、中、及格和不及格的饼图。

10)绘制总成绩和数学(math)成绩的散点图。

参考例子:

北京空气质量

派生虚拟自变量

一、将两个数据文件按学号合并为一个数据文件,得到包含所有课程成绩的数据文件。

1. 导入实验所需要的库包

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline
#如遇中文显示问题可加入以下代码
from pylab import mpl
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

import warnings
warnings.filterwarnings('ignore')

效果:导包操作成功!

2. 文件修改列名操作

file_path_1 = fr'../data/ReportCard1.txt'
file_path_2 = fr'../data/ReportCard2.txt'

# 创建一个新的列名列表
new_column_names_1 = ["学号","性别","政治","语文","数学"]
new_column_names_2 = ["学号","外语","物理","化学","地理","历史"]

data_1 = pd.read_csv(file_path_1,sep="\t")
data_1.head()

# 将新的列名列表赋值给DataFrame的columns属性  
data_1.columns = new_column_names_1
data_1.head()

效果:对比前后两个表格的表头字段!

核心代码是:dataframe.columns = new_columns,注意分隔符是“\t”!

3. 文件查看字段类型操作

核心代码是:dataframe.dtypes

4. 文件查看基本信息操作

核心代码是:dataframe.describe()

5. 文件合并和保存操作

# 检验两个文件是否含有关联字段(学号)
print('学号' in data_1.columns)
print('学号' in data_2.columns)

# 这里的外连接主要是为了避免两个文件中“学号”不匹配,预防数据丢失
df_merged  = pd.merge(data_1, data_2, on='学号',how="outer")
df_merged.head()

# 将合并后的数据保存起来
df_merged.to_csv(fr"../data/df_merge.txt",index=False,encoding="utf-8-sig",sep="\t")

核心代码是:pd.merge(df_1,df_2,on=‘关联字段’,how=“关联方式”)

二、计算每个同学的各门课程的总成绩和平均成绩。

1. 检验数据是否重复操作

# 读取数据源
df_merged = pd.read_csv(fr"../data/df_merge.txt",sep="\t")
df_merged.head()

# 判断学号是否重复
duplicates_in_A = df_merged["学号"].duplicated().any()
print(f"列'A'包含重复值吗? 经检验:{'是' if duplicates_in_A else '否'}")

# 查看多少行多少列
df_merged.shape

核心代码是:dataframe[字段].duplicated.any()

2. 检验每列缺失值操作

# 探索性分析每列缺失值情况
def Missing_column_explore(df):
    # 初始化一个列表来保存结果
    results_1 = []

    # 遍历DataFrame的每一列
    for column in df.columns:
        # 计算每列总个数
        total_count = df[column].shape[0]
        # 计算每列缺失值个数
        missing_count = df[column].isnull().sum()
        # 计算每列缺失值比例
        missing_ratio = missing_count / total_count

        # 将结果添加到结果列表中,使用字符串格式化
        result = (column, total_count, missing_count, "{:.2%}".format(missing_ratio))
        results_1.append(result)

        # 创建一个DataFrame来显示结果
    result_df_1 = pd.DataFrame(results_1, columns=['Column', 'Total Count', 'Missing Count', 'Missing Ratio'])

    return result_df_1

# 调用方法
Missing_column_explore(df_merged)

核心代码是:missing_ratio = missing_count / total_count

3. 检验每行缺失值操作

# 探索性分析每行缺失率


def Missing_row_explore(df):
    # 初始化一个列表来保存每行的详细信息
    row_details = []

    # 遍历迭代DataFrame的每一行
    for index, row in df.iterrows():
        # 计算每行元素个数
        count = df.shape[1]
        # 计算每行缺失值的数量
        missing_count = row.isnull().sum()
        # 计算每行的非缺失值数量
        non_missing_count = df.shape[1] - missing_count
        # 计算缺失率
        missing_rate = missing_count / df.shape[1]
        # 获取当前行的学号
        xue_hao = df.loc[index, "学号"]

        # 将格式化后的信息添加到列表中
        formatted_missing_rate = "{:.2%}".format(missing_rate)
        result = (xue_hao, count, non_missing_count, missing_count, formatted_missing_rate)
        row_details.append(result)

    # 将详细信息转换为DataFrame
    details_df = pd.DataFrame(row_details, columns=['学号', '全行个数', '空值个数', '非空个数', '缺失率'])

    return details_df

# 调用方法
Missing_row_explore(df_merged).head()

核心代码是:missing_rate = missing_count / df.shape[1]

4. 填充缺失值操作

# 根据业务要求:字段没有缺失率到达 60% ,仍可以保留数据
# 将缺失值进行替换操作:将null,替换为 0.0

df_merged.fillna(0.0,inplace=True)
df_merged.head()

核心代码是:dataframe.fillna(0.0,inplace=True)

5. 总成绩和平均值计算

# 因为之前验证过不会重复学号,因此每行就是一个类别axis = 1 行求值
df_merged["总成绩"] = df_merged[["政治", "语文", "数学", "外语", "物理", "化学", "地理", "历史"]].sum(axis=1)

# 平均成绩记得保留两位小数
df_merged["平均成绩"] = df_merged[["政治", "语文", "数学", "外语", "物理", "化学", "地理", "历史"]].mean(axis=1).round(2)

df_merged.head()

核心思路:多列操作

三、将数据按总成绩的降序排序。

# 由于需要赋值新对象
df_merged.sort_values(by="总成绩",ascending = False).head()

核心代码:多列操作dataframe.sort_values(by=‘排序字段’,ascending=True/False)

​​​​​​​四、按性别分别计算各门课程的平均成绩。

# 按照性别分组保留两位小数
df_merged.groupby("性别")[["政治", "语文", "数学", "外语", "物理", "化学", "地理", "历史"]].mean().round(2)

核心思路:分组后聚合

​​​​​​​五、按优、良、中、及格和不及格,对平均成绩进行分组。

# 自定义区间分组可以用 cut 函数
# 添加等级字段,左闭右开区间
bins = [0, 60, 70, 80, 90, 100]
labels = ['不及格', '及格', '中', '良', '优']


df_merged['等级'] = pd.cut(df_merged['平均成绩'], bins=bins, labels=labels)
df_merged.head()

# 从该结果看出没有“优”这个等级

核心代码:cut(自定义区间字段,自定义区间,自定义区间标签)

​​​​​​​六、按性别统计优、良、中、及格和不及格的人数。

1. 方法一:运用透视表

# 按性别和等级分组,并计算每个组的人数

# 方法一:运用透视表(透视表的方法是无法生成数据中没有记录的等级的,即使之前设置过)
grouped_1 = df_merged.pivot_table(index='性别',columns='等级', values='平均成绩', aggfunc='count', fill_value=0)                                                           # 0的字段也出现

# 输出结果
grouped_1

核心代码:dataframe.pivot(index=,columns=,values=,aggfunc=聚合操作,fill_value=0)

2. ​​​​​​​方法二:运用size()

# 方法二: size() 方法可以计算每组的个数,可以生成没有数据的等级
# 细节:reset_index 可以重置索引,美观且优雅
grouped_2 = df_merged.groupby(['性别', '等级']).size().reset_index(name='人数')
grouped_2

核心思路:生成长表函数,但0的字段也出现

​​​​​​​3. 方法三:运用 unstack()

# 方法三:unstack 方法,可以将多级索引转化为dataframe的二维形态
# 细节: 即使为 0的类别也显示
grouped_3 = df_merged.groupby(['性别', '等级']).size().unstack(fill_value=0)
grouped_3

核心思路:长表比较堆叠,所以(unstack)不要堆叠,变成宽表!

七、生成性别的虚拟自变量。

# 虚拟自变量,相当于将类别转化为 0,1这类数字,类似于热编码
df_merged.join(pd.get_dummies(df_merged["性别"])).reset_index().head()

核心代码:dataframe.join(pd.get_dummies(dataframe[虚拟自变量字段]))

​​​​​​​八、绘制总成绩的直方图。

import matplotlib.pyplot as plt
# 假设 total_scores 是包含总成绩数据的 Series
# 设置直方图的参数
plt.hist(df_merged["总成绩"], bins=10, alpha=0.7, color='b')
# 添加标题和标签
plt.title('Histogram of Total Scores')
plt.xlabel('Total Score')
plt.ylabel('Frequency')
# 显示网格
plt.grid(True)
# 显示直方图
plt.show()

​​​​​​​九、绘制平均成绩的优、良、中、及格和不及格的饼图。

import matplotlib.pyplot as plt

# 统计每个等级的数量
level_counts = df_merged['等级'].value_counts()

# 创建标签和对应的数据
labels = level_counts.index
sizes = level_counts.values

# 设置颜色和突出显示最大的部分
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#c2c2f0']

fig, ax = plt.subplots(figsize=(7, 7))  # 设置子图大小

# 绘制饼图
ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=140, shadow=True, labeldistance=1.1, textprops={'fontsize': 14})
ax.axis('equal')  # 保证是一个圆形

# 添加标题
ax.set_title('Distribution of Grades', fontsize=16)  # 使用ax.set_title来设置子图的标题

# 显示图例
plt.legend()

plt.show()

​​​​​​​十、绘制总成绩和数学(math)成绩的散点图。

import matplotlib.pyplot as plt

# 提取总成绩和数学成绩数据
total_scores = df_merged['总成绩']
math_scores = df_merged['数学']

# 绘制散点图
# 绘制散点图并设置颜色为<道蓝色>
plt.scatter(math_scores, total_scores, color='DodgerBlue')


# 添加标题和标签
plt.title('Scatter Plot', fontsize=16)


plt.xlabel('Math Scores')

plt.ylabel('Total Scores')

plt.show()

附录:数据集

数据集:ReportCard1.txt

xh    sex    poli    chi    math
   92103    2.00    NA    NA    NA
   92239    2.00    40.00    63.00    44.00
   92142    2.00    NaN    70.00    59.00
   92223    1.00    56.00    91.00    65.50
   92144    1.00    59.00    79.00    34.00
   92217    2.00    60.00    82.50    76.50
   92111    1.00    61.00    86.00    74.00
   92146    1.00    61.00    69.00    45.00
   92234    1.00    66.00    79.00    55.50
   92113    1.00    70.00    85.00    66.00
   92126    1.00    70.00    92.00    56.00
   92211    2.00    71.00    73.00    69.00
   92226    1.00    73.00    77.00    52.50
   92141    2.00    73.00    82.00    41.50
   92203    2.00    74.00    93.00    84.50
   92220    2.00    74.00    81.50    59.50
   92145    1.00    74.00    84.50    30.50
   92228    1.00    76.00    82.00    45.50
   92128    2.00    76.00    93.00    45.00
   92140    2.00    76.00    73.00    39.50
   92227    1.00    77.00    87.00    44.50
   92134    2.00    77.00    91.00    47.50
   92202    1.00    78.00    89.00    83.50
   92221    2.00    79.00    83.00    47.00
   92236    1.00    79.00    76.00    34.00
   92122    1.00    80.00    88.50    63.50
   92205    2.00    81.00    79.00    84.00
   92112    2.00    81.00    75.50    76.50
   92213    1.00    82.00    76.00    65.00
   92105    1.00    82.00    85.00    79.50
   92124    1.00    82.00    76.00    61.00
   92207    2.00    83.00    91.00    70.50
   92215    1.00    83.00    80.50    62.50
   92229    2.00    83.00    72.00    44.50
   92231    2.00    83.00    84.00    38.50
   92117    1.00    83.00    91.00    80.50
   92212    1.00    84.00    85.00    61.50
   92224    2.00    84.00    72.00    66.50
   92108    2.00    84.00    90.00    69.50
   92116    2.00    84.00    87.00    67.50
   92115    1.00    85.00    91.00    72.50
   92206    2.00    86.00    86.00    77.50
   92214    1.00    86.00    86.00    62.00
   92216    1.00    87.00    74.50    69.50
   92218    1.00    87.00    72.00    70.00
   92225    1.00    87.00    83.00    44.50
   92127    2.00    87.00    97.00    52.00
   92204    2.00    88.00    81.00    87.50
   92106    2.00    88.00    88.00    78.00
   92125    2.00    88.00    80.00    53.50
   92232    2.00    89.00    67.00    51.50
   92104    2.00    89.00    97.00    69.50
   92129    2.00    89.00    90.00    50.00
   92209    2.00    90.00    91.00    70.50
   92120    1.00    90.00    84.00    55.00
   92208    1.00    91.00    88.00    63.00
   92135    1.00    91.00    77.00    47.00
   92110    1.00    92.00    94.00    71.00
   92102    1.00    94.00    97.00    86.50
   92101    2.00    96.00    96.00    87.50

数据集:ReportCard2.txt

xh    fore    phy    che    geo    his
   92146    20.00    49.00    32.00    32.00    51.00
   92239    21.00    54.00    26.00    26.00    55.00
   92142    22.00    68.00    26.00    26.00    63.00
   92141    28.00    69.00    43.00    43.00    74.00
   92236    28.00    63.00    36.00    36.00    52.00
   92232    30.00    60.00    43.00    61.50    79.00
   92134    31.00    67.00    41.00    72.50    77.00
   92145    33.00    64.00    34.00    34.00    71.00
   92144    34.00    57.00    37.00    37.00    76.00
   92217    35.00    81.00    60.00    70.50    74.00
   92127    38.00    76.00    47.00    79.00    84.00
   92209    39.00    89.00    53.00    68.50    81.00
   92226    39.00    81.00    44.00    78.00    73.00
   92126    40.00    66.00    56.00    70.50    91.00
   92206    40.00    92.00    60.00    57.00    76.00
   92140    41.00    62.00    48.00    54.50    56.00
   92124    42.00    80.00    50.00    60.00    87.00
   92211    42.00    95.00    61.00    76.50    76.00
   92112    43.00    78.00    83.00    78.00    91.00
   92135    44.00    58.00    44.00    62.00    80.00
   92122    44.00    75.00    70.00    61.50    66.00
   92117    44.00    89.00    56.00    55.00    62.00
   92220    45.00    82.00    64.00    63.00    72.00
   92225    46.00    80.00    48.00    64.50    80.00
   92229    48.00    50.00    55.00    54.00    96.00
   92208    48.00    75.00    54.00    76.00    95.00
   92108    50.00    80.00    60.00    86.50    94.00
   92203    50.00    89.00    72.00    82.50    92.00
   92214    50.00    73.00    65.00    63.50    81.00
   92120    50.00    82.00    60.00    67.50    81.00
   92216    50.00    83.00    47.00    65.00    72.00
   92221    51.00    70.00    52.00    77.50    93.00
   92111    51.00    74.00    61.00    76.00    91.00
   92129    52.00    71.00    53.00    58.00    74.00
   92116    52.00    82.00    60.00    79.00    71.00
   92224    52.00    70.00    43.00    55.00    69.00
   92215    54.00    60.00    55.00    66.50    94.00
   92227    56.00    51.00    44.00    65.00    86.00
   92234    57.00    52.00    57.00    41.00    65.00
   92105    60.00    88.00    66.00    72.50    98.00
   92125    60.00    78.00    51.00    69.00    94.00
   92204    60.00    84.00    63.00    79.00    92.00
   92205    60.00    91.00    64.00    81.00    92.00
   92212    60.00    78.00    41.00    74.00    91.00
   92228    60.00    62.00    48.00    51.50    77.00
   92106    60.00    90.00    70.00    81.50    77.00
   92213    60.00    75.00    60.00    78.00    76.00
   92207    60.00    84.00    64.00    81.50    62.00
   92231    60.00    76.00    46.00    65.50    49.00
   92102    61.00    93.00    64.00    79.50    95.00
   92113    63.00    86.00    65.00    64.00    84.00
   92115    63.00    70.00    50.00    65.00    82.00
   92110    65.00    78.00    62.00    83.00    87.00
   92128    65.00    68.00    60.00    64.50    73.00
   92218    65.00    72.00    49.00    62.00    68.00
   92103    66.00    98.00    79.00    89.00    81.00
   92223    68.00    77.00    39.00    54.50    63.00
   92101    72.00    93.00    65.00    76.00    92.00
   92202    81.00    91.00    77.00    81.00    93.00
   92104    86.00    83.00    62.00    83.00    94.00
 

“若有理解思路疏漏,感谢大佬批评指正!”

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡林神不是猫

如果您觉得有帮助可以鼓励小卡哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值