Python學生成績影響分析


一、摘要

  該數據集來自kaggle,數據集包含了直接影響學生成績的原因,本選題應用Python網絡爬蟲方法。

二、選題背景:

  影響學生學習成績的因素很多,但就學生本身來說,對學習成績起決定作用的,主要是學生學習.的心理狀態、智能水平、學習方法和學習時間等四個方面的因素。本書根據這四個方面的因素和中學生的學習特點,以方法為線索,從提高學生的認識水平着手,幫助學生提高心理素質、促進智能發展、改進學習方法和科學安排時間。

三、過程及代碼:

 1 import numpy as np
 2 import pandas as pd
 3 import matplotlib.pyplot as plt
 4 import seaborn as sns
 5 from matplotlib.font_manager import FontProperties
 6 from sklearn.linear_model import LinearRegression
 7 from sklearn.linear_model import ElasticNet
 8 from sklearn.ensemble import RandomForestRegressor
 9 from sklearn.ensemble import ExtraTreesRegressor
10 from sklearn.ensemble import GradientBoostingRegressor
11 from sklearn.svm import SVR
12 from sklearn.model_selection import train_test_split
13 from sklearn.preprocessing import MinMaxScaler
14 from sklearn.metrics import mean_squared_error, mean_absolute_error, median_absolute_error
15 import scipy
16 import pickle
17 
18 
19 # 初始化數據
20 plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文字體設置-黑體
21 plt.rcParams['axes.unicode_minus'] = False  # 解決保存圖像是負號'-'顯示為方塊的問題
22 sns.set(font='SimHei')  # 解決Seaborn中文顯示問題
23 student = pd.read_csv('student-mat.csv')
24 # print(student.head())
25 
26 # 分析G3數據屬性
27 # print(student['G3'].describe())
1 # 根據人數多少統計各分數段的學生人數
2 grade_counts = student['G3'].value_counts().sort_values().plot.barh(width=.9,color=sns.color_palette('inferno',40))
3 grade_counts.axes.set_title('各分數值的學生分布',fontsize=30)
4 grade_counts.set_xlabel('學生數量', fontsize=30)
5 grade_counts.set_ylabel('最終成績', fontsize=30)
6 plt.show()

1 # 從低到高展示成績分布圖
2 grade_distribution = sns.countplot(student['G3'])
3 grade_distribution.set_title('成績分布圖', fontsize=30)
4 grade_distribution.set_xlabel('期末成績', fontsize=20)
5 grade_distribution.set_ylabel('人數統計', fontsize=20)
6 plt.show()
7 
8 # 檢查各個列是否有null值,如果沒有表示成績中的0分確實是0分
9 # print(student.isnull().any())

1 # 分析性別比例
2 male_studs = len(student[student['sex'] == 'M'])
3 female_studs = len(student[student['sex'] == 'F'])
4 print('男同學數量:',male_studs)
5 print('女同學數量:',female_studs)
1 # 分析年齡分布比例(曲線圖)
2 age_distribution = sns.kdeplot(student['age'], shade=True)
3 age_distribution.axes.set_title('學生年齡分布圖', fontsize=30)
4 age_distribution.set_xlabel('年齡', fontsize=20)
5 age_distribution.set_ylabel('比例', fontsize=20)
6 plt.show()

1 # 分性別年齡分布圖(柱狀圖)
2 age_distribution_sex = sns.countplot('age', hue='sex', data=student)
3 age_distribution_sex.axes.set_title('不同年齡段的學生人數', fontsize=30)
4 age_distribution_sex.set_xlabel('年齡', fontsize=30)
5 age_distribution_sex.set_ylabel('人數', fontsize=30)
6 plt.show()

1 # 各年齡段的成績箱型圖
2 age_grade_boxplot = sns.boxplot(x='age', y='G3', data=student)
3 age_grade_boxplot.axes.set_title('年齡與分數', fontsize = 30)
4 age_grade_boxplot.set_xlabel('年齡', fontsize = 20)
5 age_grade_boxplot.set_ylabel('分數', fontsize = 20)
6 plt.show()

1 # 各年齡段的成績分布圖
2 age_grade_swarmplot = sns.swarmplot(x='age', y='G3', data=student)
3 age_grade_swarmplot.axes.set_title('年齡與分數', fontsize = 30)
4 age_grade_swarmplot.set_xlabel('年齡', fontsize = 20)
5 age_grade_swarmplot.set_ylabel('分數', fontsize = 20)
6 plt.show()

1 # 城鄉學生計數
2 areas_countplot = sns.countplot(student['address'])
3 areas_countplot.axes.set_title('城鄉學生', fontsize = 30)
4 areas_countplot.set_xlabel('家庭住址', fontsize = 20)
5 areas_countplot.set_ylabel('計數', fontsize = 20)
6 plt.show()

 1 # Grade distribution by address
 2 sns.kdeplot(student.loc[student['address'] == 'U', 'G3'], label='Urban', shade = True)
 3 sns.kdeplot(student.loc[student['address'] == 'R', 'G3'], label='Rural', shade = True)
 4 plt.title('城市學生獲得了更好的成績嗎?', fontsize = 20)
 5 plt.xlabel('分數', fontsize = 20)
 6 plt.ylabel('占比', fontsize = 20)
 7 plt.show()
 8 
 9 # 選取G3屬性值
10 labels = student['G3']
11 
12 # 刪除school,G1和G2屬性
13 student = student.drop(['school', 'G1', 'G2'], axis='columns')
14 
15 # 對離散變量進行獨熱編碼
16 student = pd.get_dummies(student)
17 
18 # 選取相關性最強的8個
19 most_correlated = student.corr().abs()['G3'].sort_values(ascending=False)
20 most_correlated = most_correlated[:9]
21 print(most_correlated)

1 # 失敗次數成績分布圖
2 failures_swarmplot = sns.swarmplot(x=student['failures'],y=student['G3'])
3 failures_swarmplot.axes.set_title('失敗次數少的學生分數更高嗎?', fontsize = 30)
4 failures_swarmplot.set_xlabel('失敗次數', fontsize = 20)
5 failures_swarmplot.set_ylabel('最終成績', fontsize = 20)
6 plt.show()

1 # 雙親受教育水平的影響
2 family_ed = student['Fedu'] + student['Medu'] 
3 family_ed_boxplot = sns.boxplot(x=family_ed,y=student['G3'])
4 family_ed_boxplot.axes.set_title('雙親受教育水平的影響', fontsize = 30)
5 family_ed_boxplot.set_xlabel('家庭教育水平(Mother + Father)', fontsize = 20)
6 family_ed_boxplot.set_ylabel('最終成績', fontsize = 20)
7 plt.show()

1 # 學生自己的升學意志對成績的影響
2 personal_wish = sns.boxplot(x = student['higher_yes'], y=student['G3'])
3 personal_wish.axes.set_title('學生升學意願對成績的影響', fontsize = 30)
4 personal_wish.set_xlabel('更高級的教育 (1 = 是)', fontsize = 20)
5 personal_wish.set_ylabel('最終成績', fontsize = 20)
6 plt.show()

 1 # 分割數據集
 2 X_train, X_test, y_train, y_test = train_test_split(student, labels, test_size = 0.25, random_state=42)
 3 
 4 # 計算平均絕對誤差和均方根誤差
 5 # MAE-平均絕對誤差
 6 # RMSE-均方根誤差
 7 def evaluate_predictions(predictions, true):
 8     mae = np.mean(abs(predictions - true))
 9     rmse = np.sqrt(np.mean((predictions - true) ** 2))
10     
11     return mae, rmse
12 
13 # 求中位數
14 median_pred = X_train['G3'].median()
15 
16 # 所有中位數的列表
17 median_preds = [median_pred for _ in range(len(X_test))]
18 
19 # 存儲真實的G3值以傳遞給函數
20 true = X_test['G3']
21 
22 # 展示基准
23 mb_mae, mb_rmse = evaluate_predictions(median_preds, true)
24 print('Median Baseline  MAE: {:.4f}'.format(mb_mae))
25 print('Median Baseline RMSE: {:.4f}'.format(mb_rmse))
26 
27 # 通過訓練集訓練和測試集測試來生成多個線性模型
28 def evaluate(X_train, X_test, y_train, y_test):
29     # 模型名稱
30     model_name_list = ['Linear Regression', 'ElasticNet Regression',
31                       'Random Forest', 'Extra Trees', 'SVM',
32                        'Gradient Boosted', 'Baseline']
33     X_train = X_train.drop('G3', axis='columns')
34     X_test = X_test.drop('G3', axis='columns')
35     
36     # 實例化模型
37     model1 = LinearRegression()
38     model2 = ElasticNet(alpha=1.0, l1_ratio=0.5)
39     model3 = RandomForestRegressor(n_estimators=100)
40     model4 = ExtraTreesRegressor(n_estimators=100)
41     model5 = SVR(kernel='rbf', degree=3, C=1.0, gamma='auto')
42     model6 = GradientBoostingRegressor(n_estimators=50)
43     
44     # 結果數據框
45     results = pd.DataFrame(columns=['mae', 'rmse'], index = model_name_list)
46     
47     # 每種模型的訓練和預測
48     for i, model in enumerate([model1, model2, model3, model4, model5, model6]):
49         model.fit(X_train, y_train)
50         predictions = model.predict(X_test)
51         
52         # 誤差標准
53         mae = np.mean(abs(predictions - y_test))
54         rmse = np.sqrt(np.mean((predictions - y_test) ** 2))
55         
56         # 將結果插入結果框
57         model_name = model_name_list[i]
58         results.loc[model_name, :] = [mae, rmse]
59     
60     # 中值基准度量
61     baseline = np.median(y_train)
62     baseline_mae = np.mean(abs(baseline - y_test))
63     baseline_rmse = np.sqrt(np.mean((baseline - y_test) ** 2))
64     
65     results.loc['Baseline', :] = [baseline_mae, baseline_rmse]
66     
67     return results
68 results = evaluate(X_train, X_test, y_train, y_test)
69 print(results)
70 
71 # 找出最合適的模型
72 plt.figure(figsize=(12, 8))
73 
74 # 平均絕對誤差
75 ax =  plt.subplot(1, 2, 1)
76 results.sort_values('mae', ascending = True).plot.bar(y = 'mae', color = 'b', ax = ax, fontsize=20)
77 plt.title('平均絕對誤差', fontsize=20) 
78 plt.ylabel('MAE', fontsize=20)
79 
80 # 均方根誤差
81 ax = plt.subplot(1, 2, 2)
82 results.sort_values('rmse', ascending = True).plot.bar(y = 'rmse', color = 'r', ax = ax, fontsize=20)
83 plt.title('均方根誤差', fontsize=20) 
84 plt.ylabel('RMSE',fontsize=20)
85 plt.tight_layout()
86 plt.show()
87 
88 # 保存線性回歸模型
89 model = LinearRegression()
90 model.fit(X_train, y_train)
91 filename = 'LR_Model'
92 pickle.dump(model, open(filename, 'wb'))

完整代碼:

  1 import numpy as np
  2 import pandas as pd
  3 import matplotlib.pyplot as plt
  4 import seaborn as sns
  5 from matplotlib.font_manager import FontProperties
  6 from sklearn.linear_model import LinearRegression
  7 from sklearn.linear_model import ElasticNet
  8 from sklearn.ensemble import RandomForestRegressor
  9 from sklearn.ensemble import ExtraTreesRegressor
 10 from sklearn.ensemble import GradientBoostingRegressor
 11 from sklearn.svm import SVR
 12 from sklearn.model_selection import train_test_split
 13 from sklearn.preprocessing import MinMaxScaler
 14 from sklearn.metrics import mean_squared_error, mean_absolute_error, median_absolute_error
 15 import scipy
 16 import pickle
 17 
 18 
 19 # 初始化數據
 20 plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文字體設置-黑體
 21 plt.rcParams['axes.unicode_minus'] = False  # 解決保存圖像是負號'-'顯示為方塊的問題
 22 sns.set(font='SimHei')  # 解決Seaborn中文顯示問題
 23 student = pd.read_csv('student-mat.csv')
 24 
 25 # print(student.head())
 26 
 27 # 分析G3數據屬性
 28 # print(student['G3'].describe())
 29 
 30 # 根據人數多少統計各分數段的學生人數
 31 grade_counts = student['G3'].value_counts().sort_values().plot.barh(width=.9,color=sns.color_palette('inferno',40))
 32 grade_counts.axes.set_title('各分數值的學生分布',fontsize=30)
 33 grade_counts.set_xlabel('學生數量', fontsize=30)
 34 grade_counts.set_ylabel('最終成績', fontsize=30)
 35 plt.show()
 36 
 37 # 從低到高展示成績分布圖
 38 grade_distribution = sns.countplot(student['G3'])
 39 grade_distribution.set_title('成績分布圖', fontsize=30)
 40 grade_distribution.set_xlabel('期末成績', fontsize=20)
 41 grade_distribution.set_ylabel('人數統計', fontsize=20)
 42 plt.show()
 43 
 44 # 檢查各個列是否有null值,如果沒有表示成績中的0分確實是0分
 45 
 46 # print(student.isnull().any())
 47 
 48 # 分析性別比例
 49 male_studs = len(student[student['sex'] == 'M'])
 50 female_studs = len(student[student['sex'] == 'F'])
 51 print('男同學數量:',male_studs)
 52 print('女同學數量:',female_studs)
 53 
 54 # 分析年齡分布比例(曲線圖)
 55 age_distribution = sns.kdeplot(student['age'], shade=True)
 56 age_distribution.axes.set_title('學生年齡分布圖', fontsize=30)
 57 age_distribution.set_xlabel('年齡', fontsize=20)
 58 age_distribution.set_ylabel('比例', fontsize=20)
 59 plt.show()
 60 
 61 # 分性別年齡分布圖(柱狀圖)
 62 age_distribution_sex = sns.countplot('age', hue='sex', data=student)
 63 age_distribution_sex.axes.set_title('不同年齡段的學生人數', fontsize=30)
 64 age_distribution_sex.set_xlabel('年齡', fontsize=30)
 65 age_distribution_sex.set_ylabel('人數', fontsize=30)
 66 plt.show()
 67 
 68 # 各年齡段的成績箱型圖
 69 age_grade_boxplot = sns.boxplot(x='age', y='G3', data=student)
 70 age_grade_boxplot.axes.set_title('年齡與分數', fontsize = 30)
 71 age_grade_boxplot.set_xlabel('年齡', fontsize = 20)
 72 age_grade_boxplot.set_ylabel('分數', fontsize = 20)
 73 plt.show()
 74 
 75 # 各年齡段的成績分布圖
 76 age_grade_swarmplot = sns.swarmplot(x='age', y='G3', data=student)
 77 age_grade_swarmplot.axes.set_title('年齡與分數', fontsize = 30)
 78 age_grade_swarmplot.set_xlabel('年齡', fontsize = 20)
 79 age_grade_swarmplot.set_ylabel('分數', fontsize = 20)
 80 plt.show()
 81 
 82 # 城鄉學生計數
 83 areas_countplot = sns.countplot(student['address'])
 84 areas_countplot.axes.set_title('城鄉學生', fontsize = 30)
 85 areas_countplot.set_xlabel('家庭住址', fontsize = 20)
 86 areas_countplot.set_ylabel('計數', fontsize = 20)
 87 plt.show()
 88 
 89 # Grade distribution by address
 90 sns.kdeplot(student.loc[student['address'] == 'U', 'G3'], label='Urban', shade = True)
 91 sns.kdeplot(student.loc[student['address'] == 'R', 'G3'], label='Rural', shade = True)
 92 plt.title('城市學生獲得了更好的成績嗎?', fontsize = 20)
 93 plt.xlabel('分數', fontsize = 20)
 94 plt.ylabel('占比', fontsize = 20)
 95 plt.show()
 96 
 97 # 選取G3屬性值
 98 labels = student['G3']
 99 
100 # 刪除school,G1和G2屬性
101 student = student.drop(['school', 'G1', 'G2'], axis='columns')
102 
103 # 對離散變量進行獨熱編碼
104 student = pd.get_dummies(student)
105 
106 # 選取相關性最強的8個
107 most_correlated = student.corr().abs()['G3'].sort_values(ascending=False)
108 most_correlated = most_correlated[:9]
109 print(most_correlated)
110 
111 # 失敗次數成績分布圖
112 failures_swarmplot = sns.swarmplot(x=student['failures'],y=student['G3'])
113 failures_swarmplot.axes.set_title('失敗次數少的學生分數更高嗎?', fontsize = 30)
114 failures_swarmplot.set_xlabel('失敗次數', fontsize = 20)
115 failures_swarmplot.set_ylabel('最終成績', fontsize = 20)
116 plt.show()
117 
118 # 雙親受教育水平的影響
119 family_ed = student['Fedu'] + student['Medu'] 
120 family_ed_boxplot = sns.boxplot(x=family_ed,y=student['G3'])
121 family_ed_boxplot.axes.set_title('雙親受教育水平的影響', fontsize = 30)
122 family_ed_boxplot.set_xlabel('家庭教育水平(Mother + Father)', fontsize = 20)
123 family_ed_boxplot.set_ylabel('最終成績', fontsize = 20)
124 plt.show()
125 
126 # 學生自己的升學意志對成績的影響
127 personal_wish = sns.boxplot(x = student['higher_yes'], y=student['G3'])
128 personal_wish.axes.set_title('學生升學意願對成績的影響', fontsize = 30)
129 personal_wish.set_xlabel('更高級的教育 (1 = 是)', fontsize = 20)
130 personal_wish.set_ylabel('最終成績', fontsize = 20)
131 plt.show()
132 
133 # 分割數據集
134 X_train, X_test, y_train, y_test = train_test_split(student, labels, test_size = 0.25, random_state=42)
135 
136 # 計算平均絕對誤差和均方根誤差
137 
138 # MAE-平均絕對誤差
139 
140 # RMSE-均方根誤差
141 def evaluate_predictions(predictions, true):
142     mae = np.mean(abs(predictions - true))
143     rmse = np.sqrt(np.mean((predictions - true) ** 2))
144     
145     return mae, rmse
146 
147 # 求中位數
148 median_pred = X_train['G3'].median()
149 
150 # 所有中位數的列表
151 median_preds = [median_pred for _ in range(len(X_test))]
152 
153 # 存儲真實的G3值以傳遞給函數
154 true = X_test['G3']
155 
156 # 展示基准
157 mb_mae, mb_rmse = evaluate_predictions(median_preds, true)
158 print('Median Baseline  MAE: {:.4f}'.format(mb_mae))
159 print('Median Baseline RMSE: {:.4f}'.format(mb_rmse))
160 
161 # 通過訓練集訓練和測試集測試來生成多個線性模型
162 def evaluate(X_train, X_test, y_train, y_test):
163     
164 # 模型名稱
165     model_name_list = ['Linear Regression', 'ElasticNet Regression',
166                       'Random Forest', 'Extra Trees', 'SVM',
167                        'Gradient Boosted', 'Baseline']
168     X_train = X_train.drop('G3', axis='columns')
169     X_test = X_test.drop('G3', axis='columns')
170     
171     # 實例化模型
172     model1 = LinearRegression()
173     model2 = ElasticNet(alpha=1.0, l1_ratio=0.5)
174     model3 = RandomForestRegressor(n_estimators=100)
175     model4 = ExtraTreesRegressor(n_estimators=100)
176     model5 = SVR(kernel='rbf', degree=3, C=1.0, gamma='auto')
177     model6 = GradientBoostingRegressor(n_estimators=50)
178     
179     # 結果數據框
180     results = pd.DataFrame(columns=['mae', 'rmse'], index = model_name_list)
181     
182     # 每種模型的訓練和預測
183     for i, model in enumerate([model1, model2, model3, model4, model5, model6]):
184         model.fit(X_train, y_train)
185         predictions = model.predict(X_test)
186         
187         # 誤差標准
188         mae = np.mean(abs(predictions - y_test))
189         rmse = np.sqrt(np.mean((predictions - y_test) ** 2))
190         
191         # 將結果插入結果框
192         model_name = model_name_list[i]
193         results.loc[model_name, :] = [mae, rmse]
194     
195     # 中值基准度量
196     baseline = np.median(y_train)
197     baseline_mae = np.mean(abs(baseline - y_test))
198     baseline_rmse = np.sqrt(np.mean((baseline - y_test) ** 2))
199     
200     results.loc['Baseline', :] = [baseline_mae, baseline_rmse]
201     
202     return results
203 results = evaluate(X_train, X_test, y_train, y_test)
204 print(results)
205 
206 # 找出最合適的模型
207 plt.figure(figsize=(12, 8))
208 
209 # 平均絕對誤差
210 ax =  plt.subplot(1, 2, 1)
211 results.sort_values('mae', ascending = True).plot.bar(y = 'mae', color = 'b', ax = ax, fontsize=20)
212 plt.title('平均絕對誤差', fontsize=20) 
213 plt.ylabel('MAE', fontsize=20)
214 
215 # 均方根誤差
216 ax = plt.subplot(1, 2, 2)
217 results.sort_values('rmse', ascending = True).plot.bar(y = 'rmse', color = 'r', ax = ax, fontsize=20)
218 plt.title('均方根誤差', fontsize=20) 
219 plt.ylabel('RMSE',fontsize=20)
220 plt.tight_layout()
221 plt.show()
222 
223 # 保存線性回歸模型
224 model = LinearRegression()
225 model.fit(X_train, y_train)
226 filename = 'LR_Model'
227 pickle.dump(model, open(filename, 'wb'))

四、總結:

通過以上分析,可以初步得出以下的結論:
1.雙親受教育水平會影響孩子成績,父母學歷越高,學生成績越好
2.學生升學意願會影響學生自身成績
3.考試准備充分的同學成績較高

 


免責聲明!

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



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