大家好,又见面了,我是你们的朋友全栈
(有需要完整代码和数据的可以评论留下你的邮箱,我会尽快发送给你!)
大家早上好,本人姓吴,如果觉得文章写得还行的话也可以叫我吴老师。欢迎大家跟我一起走进数据分析的世界,一起学习! 感兴趣的朋友可以关注我或者我的数据分析专栏,里面有许多优质的文章跟大家分享哦。
提问:大家觉得成绩的高低都和哪些因素有关呢?男女生之间在科目上是否有明显的差异呢?
前言
又到了每周末知识分享环节。这次给大家分享的是kaggle上的一个非常有意思的项目,我们希望从中发现学生的测验表现与标签之间的关系。
总之,本次项目干货满满,除了通过绘图等常规手段之外,也用到了t检验等假设检验的方法来力求让结论更具说服力。
下面开始项目的正式介绍。
目录
- 前言
- 1.项目介绍
-
- 1.1 项目介绍
- 1.2 数据介绍
- 2. 数据整理
- 3. 学生成绩分析
-
- 3.1 学生整体成绩分布
- 3.2 不同学科成绩间的关联度以及不同学生人群擅长科目
- 3.3 高分学生人群画像
-
- 3.3.1 父母学历
- 3.3.2 学生性别
- 结束语
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import scipy.stats as stats
import scipy
from scipy.stats import ttest_ind
from scipy.stats import chisquare
from scipy.stats import chi2_contingency
import numpy as np
1.项目介绍
1.1 项目介绍
本文数据集来自竞赛平台Kaggle,共拥有1000条数据,并已经过脱敏处理。数据集共包含9个标签,我们希望从中发现学生的测验表现与标签之间的关系。
1.2 数据介绍
以下标签解释:
- Unnamed:学生编号
- race/ethnicity:种族
- parental level of education:父母受教育程度
- bachelor’s degree: 学士学位
- some college:大学肄业
- master’s degree:硕士学位
- associate’s degree:副学士
- high school:高中
- some high school:高中肄业
- lunch:午餐花费
- Standard: 标准
- free/reduced: 学校免费提供或低于标准
- test preparation course: 是否完成与考试相关课程
- none: 未完成
- completed: 完成
- math percentage:数学成绩
- reading score percentage: 阅读成绩
- writing score percentage: 写作成绩
- sex: 性别
2. 数据整理
代码语言:javascript复制data = pd.read_csv('Student Performance new.csv')
代码语言:javascript复制data.info()
代码语言:javascript复制<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Unnamed: 0 1000 non-null int64
1 race/ethnicity 1000 non-null object
2 parental level of education 1000 non-null object
3 lunch 1000 non-null object
4 test preparation course 1000 non-null object
5 math percentage 1000 non-null float64
6 reading score percentage 1000 non-null float64
7 writing score percentage 1000 non-null float64
8 sex 1000 non-null object
dtypes: float64(3), int64(1), object(5)
memory usage: 70.4 KB
本数据集共包含1000条数据,无数据缺失,数据类型包括整数,浮点数与对象类型
代码语言:javascript复制data.sample(n=5) # 随机抽取数据查看
Unnamed: 0 | race/ethnicity | parental level of education | lunch | test preparation course | math percentage | reading score percentage | writing score percentage | sex | |
---|---|---|---|---|---|---|---|---|---|
113 | 113 | group D | some college | standard | none | 0.51 | 0.58 | 0.54 | F |
342 | 342 | group B | high school | standard | completed | 0.69 | 0.76 | 0.74 | F |
475 | 475 | group D | bachelor’s degree | standard | completed | 0.71 | 0.76 | 0.83 | F |
181 | 181 | group C | some college | free/reduced | none | 0.46 | 0.64 | 0.66 | F |
41 | 41 | group C | associate’s degree | standard | none | 0.58 | 0.73 | 0.68 | F |
# 数据Unnamed列为学生编号,我们将其舍弃
data = data.drop(columns=['Unnamed: 0'], axis=1)
对于部分标签,存在多个变量, 我们需要对其进一步观察
代码语言:javascript复制labels = ['race/ethnicity', 'parental level of education', 'lunch', 'test preparation course']
for label in labels:
print(f'标签{
label}情况:')
print(f'共有{
data[label].nunique()}个变量,分别为')
print(data[label].unique())
print('*'*20)
代码语言:javascript复制标签race/ethnicity情况:
共有5个变量,分别为
['group B' 'group C' 'group A' 'group D' 'group E']
********************
标签parental level of education情况:
共有6个变量,分别为
["bachelor's degree" 'some college' "master's degree" "associate's degree"
'high school' 'some high school']
********************
标签lunch情况:
共有2个变量,分别为
['standard' 'free/reduced']
********************
标签test preparation course情况:
共有2个变量,分别为
['none' 'completed']
********************
对于分数标签,我们增加一列平均分(average score)
代码语言:javascript复制average_score = data[['math percentage', 'reading score percentage', 'writing score percentage']].mean(axis=1)
data.insert(7, 'average score', np.round(average_score, 2))
在此基础上,我们对average_score进行分箱,以0-59,60-69,70-79,80-89,90-100为分隔,将分数分为对应的F, D, C, B, A。
代码语言:javascript复制performance_level = pd.cut(data['average score'], bins=[0, 0.59, 0.69, 0.79, 0.89, 100],
labels=['F', 'D', 'C', 'B', 'A'] )
data.insert(8, 'performance level', performance_level)
代码语言:javascript复制data.groupby('sex')['sex'].count()
代码语言:javascript复制sex
F 518
M 482
Name: sex, dtype: int64
本数据集男女比例为:48.2%比51.8%。我们认为其基本符合男女比例在美国的分布,为了进一步进行验证,我们可以引入卡方拟合度检验:
- H0:在选取数据集时,男性与女性被选中的概率皆为50%
- H0:上述概率不成立
expected_number = [500, 500] # 理论上1000个样本中男女人数
observed_number = [482, 518] # 实际观察到的男女人数
result = stats.chisquare(f_obs=observed_number, f_exp=expected_number)
print(f'卡方拟合度检验的P值为:{
result[1]}')
代码语言:javascript复制卡方拟合度检验的P值为:0.25494516431731784
据此,我们可以认为,如果从男女比例出发,这份数据为随机抽取。
至此,数据整理结束,我们再次查看此时的数据情况。
代码语言:javascript复制data.sample(n=5)
race/ethnicity | parental level of education | lunch | test preparation course | math percentage | reading score percentage | writing score percentage | average score | performance level | sex | |
---|---|---|---|---|---|---|---|---|---|---|
801 | group C | some high school | standard | completed | 0.76 | 0.80 | 0.73 | 0.76 | C | M |
200 | group C | associate’s degree | standard | completed | 0.67 | 0.84 | 0.86 | 0.79 | C | F |
417 | group C | associate’s degree | standard | none | 0.74 | 0.73 | 0.67 | 0.71 | C | M |
629 | group C | some high school | standard | completed | 0.44 | 0.51 | 0.55 | 0.50 | F | F |
944 | group B | high school | standard | none | 0.58 | 0.68 | 0.61 | 0.62 | D | F |
3. 学生成绩分析
3.1 学生整体成绩分布
代码语言:javascript复制fig = plt.figure(figsize=(5,10))
sns.set_style('darkgrid')
subjects = ['math percentage', 'reading score percentage', 'writing score percentage', 'average score']
color = ['green', 'blue', 'orange', 'purple']
column = 1
for subject in subjects:
plt.subplot(len(subjects), 1, column)
sns.kdeplot(data=data, x=subject, color=color[column - 1])
column = column 1
plt.tight_layout()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zWSG3rHk-1639906825714)(output_26_0.png)]
整体来看,各学科成绩与平均成绩都符合正态分布,我们以样本均值加减两个标准差,可以得到约95%的学生成绩分区间:
代码语言:javascript复制lower_bound = data['average score'].mean() - data['average score'].std()*2
upper_bound = data['average score'].mean() data['average score'].std()*2
print(f'95%的学生成绩分布下限:{
lower_bound}')
print(f'95%的学生成绩分布上限:{
upper_bound}')
代码语言:javascript复制95%的学生成绩分布下限:0.3924529214957264
95%的学生成绩分布上限:0.9627870785042743
即约有95%的学生成绩分布在0.39分至0.96分之间。
3.2 不同学科成绩间的关联度以及不同学生人群擅长科目
我们数据集中共拥有三门学科,分别为读写与数学。我们可以分别将其看做**“文科”与“理科”**,并分别查看不同学科成绩之间的关联度。
代码语言:javascript复制data[subjects].corr()
math percentage | reading score percentage | writing score percentage | average score | |
---|---|---|---|---|
math percentage | 1.000000 | 0.817580 | 0.802642 | 0.918442 |
reading score percentage | 0.817580 | 1.000000 | 0.954598 | 0.970143 |
writing score percentage | 0.802642 | 0.954598 | 1.000000 | 0.965643 |
average score | 0.918442 | 0.970143 | 0.965643 | 1.000000 |
fig = plt.figure()
plt.subplot()
sns.heatmap(data[subjects].corr(), annot=True)
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWpxCHDy-1639906825715)(output_33_0.png)]
从上面的表与图中,我们可以看出,“文科”学科成绩之间的相关程度,要高于“文科”与“理科”学科成绩之间的相关程度。而且考虑到本数据集中“文科”的科目要多于“理科”的科目,“文科”成绩与平均成绩的相关程度更高。
一般意义而言,社会认为上男生更擅长理科,而女生更擅长文科。我们将使用统计学验证这一看法是否适用于本数据集。
我们引入卡方独立性检验,判断性别与学科掌握程度方面是否是独立不相关的。
- H0:数学成绩与性别无关系。
- H1: 数学成绩与性别有关系。
# 将数学成绩进行分箱,分箱方式与前述对平均成绩的分箱方式相关
math_grading = pd.cut(data['math percentage'], bins=[0, 0.59, 0.69, 0.79, 0.89, 100],
labels=['F', 'D', 'C', 'B', 'A'] )
crosstab = pd.crosstab(math_grading, data['sex'])
代码语言:javascript复制# 引入卡方独立性检验
result = stats.chi2_contingency(crosstab)
print(f'p值为:{
result[1]}')
代码语言:javascript复制p值为:3.052111718576621e-05
**原假设不成立,即学生的数学成绩与性别并不独立。**在此基础上,我们进一步查看不同性别下,学生在数学科目的表现。
代码语言:javascript复制data.groupby('sex')[['math percentage']].agg([np.mean, np.median])
math percentage | ||
---|---|---|
mean | median | |
sex | ||
F | 0.636332 | 0.65 |
M | 0.687282 | 0.69 |
fig, ax = plt.subplots(1,2, figsize=(10, 5))
sns.boxplot(data=data, y='math percentage', x='sex', palette='summer', ax=ax[0])
sns.histplot(data=data, x='math percentage', hue='sex', fill=True, ax=ax[1], stat='probability')
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qV7fOTYc-1639906825716)(output_41_0.png)]
在数学科目的平均分以及中位数两大统计指标上,我们可以看出,男性在该科目的确占有一定优势。两者的数学成绩分布大致都符合正态分布,但男性在样本方差明显更小,且在高分部分,男性出现的概率更大——男性在数学上的整体表现,要优于女性。
下面我们继续观察男女性在文科科目上的表现,在这里,我们选取writing score percentage标签,做为研究对象。
代码语言:javascript复制data.groupby('sex')[['writing score percentage']].agg([np.mean, np.median])
writing score percentage | ||
---|---|---|
mean | median | |
sex | ||
F | 0.724672 | 0.74 |
M | 0.633112 | 0.64 |
fig = px.histogram(
data, x='writing score percentage',
marginal='box', opacity=0.6,
color='sex',
histnorm='probability',
title='男生与女生在文科上的表现',
template='plotly_white'
)
fig.update_layout(barmode='overlay', width=800)
fig.show()
从所估计的概率密度图上看,女生在writing score percentage的高分领域,女性出现的概率要远高于男生,而在低分领域则正好相反。综合来看男生,男生的确更擅长理科,而女生则相反。
3.3 高分学生人群画像
3.3.1 父母学历
下面我们分析高分(均分高于90分)考生的画像,首先我们探究高分与父母受教育程度间的关系。
代码语言:javascript复制honor_students = data.loc[data['average score']>=0.9] # 选取均分高于0.9的学生,组成子数据集honor_students
代码语言:javascript复制honor_count = honor_students['parental level of education'].value_counts().sort_index()
total_count = data['parental level of education'].value_counts().sort_index()
fig = make_subplots(rows=1, cols=2, specs=[[dict(type='domain'),{
'type':'domain'}]])
fig.add_pie(
values=total_count.values, hole=0.4, labels=total_count.index,
row=1, col=1, name='整体学生父母受教育程度'
)
fig.add_pie(
values=honor_count.values, hole=0.4, labels=honor_count.index,
row=1, col=2, name='高分学生父母受教育程度'
)
fig.update_layout(
title_text="学生父母受教育程度",
annotations=[dict(text='整体父母', x=0.15, y=0.5, font_size=20, showarrow=False),
dict(text='高分父母', x=0.85, y=0.5, font_size=20, showarrow=False)],
width=900
)
fig.show()
从上图所示,我们发现,高分考生父母的教育程度,要高于整体考生父母的教育程度,其中高分考生父母拥有副学士、学士、硕士的比例,相较于整体考生,分别从22.9%, 11.8%, 5.9%上升至31.5%, 24.1%, 11.1%。
整体来看,高分学生的父母,约有90%都曾接受过大学教育。
不仅仅是高分学生父母的所受教育程序较高,实际上,在本数据集中,所有学生的平均分,皆与父母的教育程度正相关。下表给出了不同教育程度的父母,以及对应考生群体平均分。其中,其中学历为硕士与高中的父母,子女的平均分分别为73分及63分。
代码语言:javascript复制data.groupby('parental level of education')['average score'].mean().sort_values()
代码语言:javascript复制parental level of education
high school 0.631224
some high school 0.650726
some college 0.684469
associate's degree 0.695586
bachelor's degree 0.719492
master's degree 0.735763
Name: average score, dtype: float64
代码语言:javascript复制parents = data['parental level of education'].unique()
sample_data = []
for parent in parents:
member = data[data['parental level of education'] == parent].sample(n=30, random_state=1)
sample_data.append(member)
parent_data = pd.concat(sample_data, axis=0)
fig = px.scatter(
parent_data, x='math percentage', y='writing score percentage',
color='parental level of education',
size='average score',
title='父母教育程度对学生成绩影响',
template='plotly_dark'
)
fig.show()
上述气泡图抽取各个教育水平的父母各30名,并观察其子女成绩表现。不难看出,学生的成绩表现与父母受教育程度成正相关关系,即父母受教育程度越高,子女的学业表现越好。
为了进一步在统计学上证明这一点,我们引入卡方独立性检验:
- H0: 学生成绩表现与父母受教育程序无关
- H1: 学生成绩表现与父母受程序程度相关
crosstab = pd.crosstab(data['parental level of education'], data['performance level'])
代码语言:javascript复制result = stats.chi2_contingency(crosstab)
if result[1] < 0.05:
print(f'p值为{
result[1]}, 原假设不成立!')
else:
print(f'p值为{
result[1]}, 原假设成立!')
代码语言:javascript复制p值为0.00014895457933147155, 原假设不成立!
结论:对于高分段的学生,其父母所受的教育程度要更高。
3.3.2 学生性别
代码语言:javascript复制honor_students.groupby('sex')['sex'].count()
代码语言:javascript复制sex
F 40
M 14
Name: sex, dtype: int64
从上图表格中,我们发现高分学生当中,女性的数量要明显多于男性数量。但考虑到在三门科目当中,写作与阅读都偏向于女生所擅长的文科类科目,这对于擅长数学的男生而言,显然是不利的,我们考虑选取一门文科与一门理科,取其均值,查看在这一情况下,高分学生在男女中的分布。
代码语言:javascript复制condition = ((data['math percentage'] data['writing score percentage'])/2 >= 0.9)
data[condition].groupby('sex')['sex'].count()
代码语言:javascript复制sex
F 35
M 18
Name: sex, dtype: int64
此时,女生仍然相较于男生,仍然拥有更大的优势!
代码语言:javascript复制honor_index = honor_students.groupby('sex')['sex'].count().index
honor_value = honor_students.groupby('sex')['sex'].count().values
math_writing_index = data[condition].groupby('sex')['sex'].count().index
math_writing_value = data[condition].groupby('sex')['sex'].count().values
fig = go.Figure(data=[
go.Bar(x=honor_index, y=honor_value, name='三科均分高于90分', text=honor_value,),
go.Bar(x=math_writing_index, y=math_writing_value, name='数学写作均分高于90分', text=math_writing_value)
])
fig.update_layout(width=500, height=400)
fig.show()
从我们得到的结果来看,无论是哪种情况,女生高分情况都要远胜于男生,基于此,我们做出一个假设:尽管女生在数学方面整体不如男性,但在高分段,男女生在数学的表现基本一致。
代码语言:javascript复制data[data['math percentage']>0.9].groupby('sex')['math percentage'].mean()
代码语言:javascript复制sex
F 0.952857
M 0.948621
Name: math percentage, dtype: float64
上表所示为男生与女生在高分段的数学平均成绩。
代码语言:javascript复制data[data['math percentage']>0.9].groupby('sex')['math percentage'].std()
代码语言:javascript复制sex
F 0.031803
M 0.032373
Name: math percentage, dtype: float64
上表所示为男生与女生在高分段的数学样本方差。
从数学高分段的均值及方差来看,两者都十分接近。为了进一步验证我们的观点,我们引入t 检验,判断两者的均值是否相同。
- H0: 在高分段,男生与女生在数学方面的均值一致
- H1: 在高分段,男生与女生在数学方面的均值不一致
honored_male_math = data.loc[(data['math percentage'] >= 0.9) & (data['sex'] == 'M'),'math percentage']
honored_female_math = data.loc[(data['math percentage'] >= 0.9) & (data['sex'] == 'F'),'math percentage']
result = ttest_ind(honored_male_math.values, honored_female_math.values, equal_var=True)
if result[1]>0.95:
print(f'两者的均值一致,P值为{
result[1]}')
else:
print(f'两者的均值不一致,P值为{
result[1]}')
代码语言:javascript复制两者的均值一致,P值为1.0
从P值所反馈结果来看,女生尽管整体在数学方面不如男生,但在高分段,女生与男生的表,并无明显区别。
结论:高分段,女生比男生要更占优势,而男生的优势科目在高分段,优势并不明显。
结束语
看完这篇,还有更多知识点分享给你哦,自己慢慢找哈,就在下面链接。
推荐关注的专栏