大家好,我是老吳,大家也可以叫我吳同學,再小一點的朋友也可以叫我吳師兄,歡迎大家跟我一起走進資料分析的世界,一起學習!
感興趣的朋友可以關注我或者我的資料分析專欄,里面有許多優質的文章跟大家分享哦,
提問:大家覺得成績的高低都和哪些因素有關呢?男女生之間在科目上是否有明顯的差異呢?
前言
又到了每周末知識分享環節,這次給大家分享的是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. 資料整理
data = pd.read_csv('Student Performance new.csv')
data.info()
<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條資料,無資料缺失,資料型別包括整數,浮點數與物件型別
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)
對于部分標簽,存在多個變數, 我們需要對其進一步觀察
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)
標簽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)
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,
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)
data.groupby('sex')['sex'].count()
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]}')
卡方擬合度檢驗的P值為:0.25494516431731784
據此,我們可以認為,如果從男女比例出發,這份資料為隨機抽取,
至此,資料整理結束,我們再次查看此時的資料情況,
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 學生整體成績分布
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%的學生成績磁區間:
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}')
95%的學生成績分布下限:0.3924529214957264
95%的學生成績分布上限:0.9627870785042743
即約有95%的學生成績分布在0.39分至0.96分之間,
3.2 不同學科成績間的關聯度以及不同學生人群擅長科目
我們資料集中共擁有三門學科,分別為讀寫與數學,我們可以分別將其看做**“文科”與“理科”**,并分別查看不同學科成績之間的關聯度,
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'])
# 引入卡方獨立性檢驗
result = stats.chi2_contingency(crosstab)
print(f'p值為:{result[1]}')
p值為:3.052111718576621e-05
**原假設不成立,即學生的數學成績與性別并不獨立,**在此基礎上,我們進一步查看不同性別下,學生在數學科目的表現,
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標簽,做為研究物件,
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分)考生的畫像,首先我們探究高分與父母受教育程度間的關系,
honor_students = data.loc[data['average score']>=0.9] # 選取均分高于0.9的學生,組成子資料集honor_students
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分,
data.groupby('parental level of education')['average score'].mean().sort_values()
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
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'])
result = stats.chi2_contingency(crosstab)
if result[1] < 0.05:
print(f'p值為{result[1]}, 原假設不成立!')
else:
print(f'p值為{result[1]}, 原假設成立!')
p值為0.00014895457933147155, 原假設不成立!
結論:對于高分段的學生,其父母所受的教育程度要更高,
3.3.2 學生性別
honor_students.groupby('sex')['sex'].count()
sex
F 40
M 14
Name: sex, dtype: int64
從上圖表格中,我們發現高分學生當中,女性的數量要明顯多于男性數量,但考慮到在三門科目當中,寫作與閱讀都偏向于女生所擅長的文科類科目,這對于擅長數學的男生而言,顯然是不利的,我們考慮選取一門文科與一門理科,取其均值,查看在這一情況下,高分學生在男女中的分布,
condition = ((data['math percentage']+data['writing score percentage'])/2 >= 0.9)
data[condition].groupby('sex')['sex'].count()
sex
F 35
M 18
Name: sex, dtype: int64
此時,女生仍然相較于男生,仍然擁有更大的優勢!
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()
從我們得到的結果來看,無論是哪種情況,女生高分情況都要遠勝于男生,基于此,我們做出一個假設:盡管女生在數學方面整體不如男性,但在高分段,男女生在數學的表現基本一致,
data[data['math percentage']>0.9].groupby('sex')['math percentage'].mean()
sex
F 0.952857
M 0.948621
Name: math percentage, dtype: float64
上表所示為男生與女生在高分段的數學平均成績,
data[data['math percentage']>0.9].groupby('sex')['math percentage'].std()
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 = honored_male_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]}')
兩者的均值一致,P值為1.0
從P值所反饋結果來看,女生盡管整體在數學方面不如男生,但在高分段,女生與男生的表,并無明顯區別,
結論:高分段,女生比男生要更占優勢,而男生的優勢科目在高分段,優勢并不明顯,
結束語
看完這篇,還有更多知識點分享給你哦,自己慢慢找哈,就在下面鏈接,
推薦關注的專欄
👨?👩?👦?👦 機器學習:分享機器學習實戰專案和常用模型講解
👨?👩?👦?👦 資料分析:分享資料分析實戰專案和常用技能整理
往期內容回顧
💚 學習Python全套代碼【超詳細】Python入門、核心語法、資料結構、Python進階【致那個想學好Python的你】
?? 學習pandas全套代碼【超詳細】資料查看、輸入輸出、選取、集成、清洗、轉換、重塑、數學和統計方法、排序
💙 學習pandas全套代碼【超詳細】分箱操作、分組聚合、時間序列、資料可視化
💜 學習NumPy全套代碼【超詳細】基本操作、資料型別、陣列運算、復制和試圖、索引、切片和迭代、形狀操作、通用函式、線性代數
關注我,了解更多相關知識!
CSDN@報告,今天也有好好學習
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/386596.html
標籤:python
