基于机器学习的【校园受霸凌者】预测分析
通过对校园霸凌数据特征分析、空置处理、序列化,再通过8种模型对受霸凌者预测分析,获取最有结果。
·
★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>
1.背景描述
本数据集来自全球校内学生健康调查(GSHS)是一项以学校为基础的调查,调查使用自填式问卷来获取年轻人的健康行为和与发病和死亡的主要原因有关的保护因素的数据。
该调查于2018年在阿根廷进行。共有56,981名学生参加。
学校回复率为86%,学生回复率为74%,总体回复率为63%。
2.数据说明
字段 | 说明 |
---|---|
Bullied on school property in past 12 months, | 在过去的12个月里,在学校范围内受到霸凌 |
Bullied not on school property in past 12_months | 在过去的12个月里,在学校以外的地方受到过霸凌 |
Cyber bullied in past 12 months | 过去12个月内被网络霸凌的情况 |
Custom Age | 自定义年龄 |
Sex | 性别 |
Physically attacked | 身体受到攻击 |
Physical fighting | 身体对抗 |
Felt lonely | 感到孤独 |
Close friends | 亲密的朋友 |
Miss school no permission | 未经学校许可的缺勤天数 |
Other students kind and helpful | 其他学生的善意和帮助 |
Parents understand problems | 父母是否知情 |
Most of the time or always felt lonely | 大部分时间或总是感到孤独 |
Missed classes or school without permission | 未经允许而缺课或旷课 |
Were underweight | 是否体重过轻 |
Were overweight | 是否体重过重 |
Were obese | 是否肥胖 |
3.问题描述
通常,霸凌与孤独感、缺乏亲密朋友、与父母沟通不畅、缺课等有关。(例如,Nansel等人在美国青年中的欺凌行为:普遍性和与社会心理适应的联系)。调查数据显示,被霸凌者多为体重不足、超重和肥胖的人。
二、数据处理
1.读取数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import os
df = pd.read_csv("data/data208695/Bullying_Dataset.csv",sep=',')
df.head()
序号 | 过去12个月内受到校内霸凌 | 过去12个月内校外受到霸凌 | 过去12个月内受到网络霸凌 | 年龄 | 性别 | 身体受到攻击 | 身体对抗 | 感到孤独 | 亲密的朋友 | 未经学校许可的缺勤天数 | 其他学生的善意和帮助 | 父母了解问题 | 大部分时间或总是感到孤独 | 未经允许而缺课或旷课 | 体重过轻 | 体重过重 | 肥胖 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | Yes | Yes | 13 | Female | 0 times | 0 times | Always | 2 | 10 or more days | Never | Always | Yes | Yes | ||||
1 | 2 | No | No | No | 13 | Female | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No | |||
2 | 3 | No | No | No | 14 | Male | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No | No | No | No |
3 | 4 | No | No | No | 16 | Male | 0 times | 2 or 3 times | Never | 3 or more | 0 days | Sometimes | No | No | No | No | No | |
4 | 5 | No | No | No | 13 | Female | 0 times | 0 times | Rarely | 3 or more | 0 days | Most of the time | Most of the time | No | No |
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 56981 entries, 0 to 56980
Data columns (total 18 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 序号 56981 non-null int64
1 过去12个月内受到校内霸凌 56981 non-null object
2 过去12个月内校外受到霸凌 56981 non-null object
3 过去12个月内受到网络霸凌 56981 non-null object
4 年龄 56981 non-null object
5 性别 56981 non-null object
6 身体受到攻击 56981 non-null object
7 身体对抗 56981 non-null object
8 感到孤独 56981 non-null object
9 亲密的朋友 56981 non-null object
10 未经学校许可的缺勤天数 56981 non-null object
11 其他学生的善意和帮助 56981 non-null object
12 父母了解问题 56981 non-null object
13 大部分时间或总是感到孤独 56981 non-null object
14 未经允许而缺课或旷课 56981 non-null object
15 体重过轻 56981 non-null object
16 体重过重 56981 non-null object
17 肥胖 56981 non-null object
dtypes: int64(1), object(17)
memory usage: 7.8+ MB
2.统计空值
对于内容为空白的,替换为空值
df.replace(r'^\s*$', np.nan, regex=True, inplace=True)
- ^ 代表开始
- $ 代表结束
- \s 空白字符
-
- 代表多次
df.replace(r'^\s*$', np.nan, regex=True, inplace=True)
df.isnull().sum()
序号 0
过去12个月内受到校内霸凌 1239
过去12个月内校外受到霸凌 489
过去12个月内受到网络霸凌 571
年龄 108
性别 536
身体受到攻击 240
身体对抗 268
感到孤独 366
亲密的朋友 1076
未经学校许可的缺勤天数 1864
其他学生的善意和帮助 1559
父母了解问题 2373
大部分时间或总是感到孤独 366
未经允许而缺课或旷课 1864
体重过轻 20929
体重过重 20929
肥胖 20929
dtype: int64
体重过轻 、体重过重、肥胖 这几类空值很多,可以不用算在特整理。
3.缺失值可视化
主要是中文显示,aistudio目前内置了中文字题,需要特别声明。
import warnings
warnings.filterwarnings("ignore")
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
%matplotlib inline
# 设置显示中文
matplotlib.rcParams['font.sans-serif'] = ['FZSongYi-Z13S'] # 指定默认字体
matplotlib.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# 各列缺失值百分比
missing_perc = (df.isnull().sum() / len(df)) * 100
# 降序排列
missing_perc_sorted = missing_perc.sort_values(ascending=False)
# 计算缺失值的累积百分比
cumulative_perc = missing_perc_sorted.cumsum()
# 制作一个帕累托图表
fig, ax1 = plt.subplots(figsize=(10, 6))
ax1.bar(missing_perc_sorted.index, missing_perc_sorted.values, color='tab:blue')
ax1.set_xlabel('特征')
ax1.set_ylabel('缺失值比例', color='tab:blue')
ax1.set_xticklabels(missing_perc_sorted.index, rotation=90)
# 为累积百分比添加第二个y轴
ax2 = ax1.twinx()
ax2.plot(missing_perc_sorted.index, cumulative_perc.values, color='tab:red', marker='o')
ax2.set_ylabel('累积百分数', color='tab:red')
# 旋转x轴标签以便更好地显示
plt.xticks(rotation=90)
# 显示
plt.show()
4.删除缺失值较多的 特征列
# Drop columns with a high proportion of missing values
df.drop(['肥胖', '体重过轻', '体重过重'], axis=1, inplace=True)
#dropping na values
df=df.dropna()
5.空值检查
# 各列非空值统计
non_null_counts = df.count()
# 检查是否所有列都有相同的非空值计数
if non_null_counts.nunique() == 1:
print("Total null values:", df.isnull().sum().sum())
else:
print("Columns have different counts of non-null values.")
Total null values: 0
df.head()
序号 | 过去12个月内受到校内霸凌 | 过去12个月内校外受到霸凌 | 过去12个月内受到网络霸凌 | 年龄 | 性别 | 身体受到攻击 | 身体对抗 | 感到孤独 | 亲密的朋友 | 未经学校许可的缺勤天数 | 其他学生的善意和帮助 | 父母了解问题 | 大部分时间或总是感到孤独 | 未经允许而缺课或旷课 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | No | No | No | 13 | Female | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No |
2 | 3 | No | No | No | 14 | Male | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No |
4 | 5 | No | No | No | 13 | Female | 0 times | 0 times | Rarely | 3 or more | 0 days | Most of the time | Most of the time | No | No |
5 | 6 | No | No | No | 13 | Male | 0 times | 1 time | Never | 3 or more | 0 days | Most of the time | Always | No | No |
6 | 7 | No | No | No | 14 | Female | 1 time | 0 times | Sometimes | 3 or more | 0 days | Most of the time | Always | No | No |
df.head()
序号 | 过去12个月内受到校内霸凌 | 过去12个月内校外受到霸凌 | 过去12个月内受到网络霸凌 | 年龄 | 性别 | 身体受到攻击 | 身体对抗 | 感到孤独 | 亲密的朋友 | 未经学校许可的缺勤天数 | 其他学生的善意和帮助 | 父母了解问题 | 大部分时间或总是感到孤独 | 未经允许而缺课或旷课 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | No | No | No | 13 | Female | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No |
2 | 3 | No | No | No | 14 | Male | 0 times | 0 times | Never | 3 or more | 0 days | Sometimes | Always | No | No |
4 | 5 | No | No | No | 13 | Female | 0 times | 0 times | Rarely | 3 or more | 0 days | Most of the time | Most of the time | No | No |
5 | 6 | No | No | No | 13 | Male | 0 times | 1 time | Never | 3 or more | 0 days | Most of the time | Always | No | No |
6 | 7 | No | No | No | 14 | Female | 1 time | 0 times | Sometimes | 3 or more | 0 days | Most of the time | Always | No | No |
三、特征处理
1.特征分类变量序列化
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
# 除去序号列
columns=df.columns[1:]
print(len(columns))
for column in columns:
print(column)
14
过去12个月内受到校内霸凌
过去12个月内校外受到霸凌
过去12个月内受到网络霸凌
年龄
性别
身体受到攻击
身体对抗
感到孤独
亲密的朋友
未经学校许可的缺勤天数
其他学生的善意和帮助
父母了解问题
大部分时间或总是感到孤独
未经允许而缺课或旷课
for column in columns:
print(f"完成 {column} 列序列化")
df[column]=le.fit_transform(df[column])
完成 过去12个月内受到校内霸凌 列序列化
完成 过去12个月内校外受到霸凌 列序列化
完成 过去12个月内受到网络霸凌 列序列化
完成 年龄 列序列化
完成 性别 列序列化
完成 身体受到攻击 列序列化
完成 身体对抗 列序列化
完成 感到孤独 列序列化
完成 亲密的朋友 列序列化
完成 未经学校许可的缺勤天数 列序列化
完成 其他学生的善意和帮助 列序列化
完成 父母了解问题 列序列化
完成 大部分时间或总是感到孤独 列序列化
完成 未经允许而缺课或旷课 列序列化
df.head()
序号 | 过去12个月内受到校内霸凌 | 过去12个月内校外受到霸凌 | 过去12个月内受到网络霸凌 | 年龄 | 性别 | 身体受到攻击 | 身体对抗 | 感到孤独 | 亲密的朋友 | 未经学校许可的缺勤天数 | 其他学生的善意和帮助 | 父母了解问题 | 大部分时间或总是感到孤独 | 未经允许而缺课或旷课 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 3 | 0 | 4 | 0 | 0 | 0 |
2 | 3 | 0 | 0 | 0 | 3 | 1 | 0 | 0 | 2 | 3 | 0 | 4 | 0 | 0 | 0 |
4 | 5 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 3 | 3 | 0 | 1 | 1 | 0 | 0 |
5 | 6 | 0 | 0 | 0 | 2 | 1 | 0 | 1 | 2 | 3 | 0 | 1 | 0 | 0 | 0 |
6 | 7 | 0 | 0 | 0 | 3 | 0 | 1 | 0 | 4 | 3 | 0 | 1 | 0 | 0 | 0 |
2.数据集切分
from sklearn.model_selection import train_test_split
# 切分数据集为 训练集 、 测试集
X = df.drop(['序号', '身体受到攻击'], axis=1)
y = df['身体受到攻击']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=2023)
四、模型训练
!pip install catboost
1.决策树预测 Decision Tree Classifier
import xgboost
import lightgbm
from sklearn.svm import SVC
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from catboost import CatBoostClassifier
# 训练决策树分类器
clf = DecisionTreeClassifier(random_state=1024)
clf.fit(X_train, y_train)
accuracy_list = []
# test数据集预测
y_pred = clf.predict(X_test)
from sklearn.metrics import accuracy_score
# 评估精度
accuracy = accuracy_score(y_test, y_pred)
print("精度: %.4f%%" % (accuracy * 100.0))
accuracy_list.append(accuracy*100)
精度: 76.2585%
2.随机森林 RandomForestClassifier
from sklearn.ensemble import RandomForestClassifier
r_clf = RandomForestClassifier(max_features=0.5, max_depth=15, random_state=1)
r_clf.fit(X_train, y_train)
r_pred = r_clf.predict(X_test)
r_acc = accuracy_score(y_test, r_pred)
print(r_acc)
accuracy_list.append(100*r_acc)
0.8279972416510688
3.逻辑回归Logistic Regression
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
log_reg_pred = log_reg.predict(X_test)
log_reg_acc = accuracy_score(y_test, log_reg_pred)
print(log_reg_acc)
accuracy_list.append(100*log_reg_acc)
0.8344990641316127
4.支持向量机Support Vector
sv_clf = SVC()
sv_clf.fit(X_train, y_train)
sv_clf_pred = sv_clf.predict(X_test)
sv_clf_acc = accuracy_score(y_test, sv_clf_pred)
print(sv_clf_acc)
accuracy_list.append(100* sv_clf_acc)
0.8360752635208354
5.K临近算法K Neighbors Classifier
kn_clf = KNeighborsClassifier(n_neighbors=6)
kn_clf.fit(X_train, y_train)
kn_pred = kn_clf.predict(X_test)
kn_acc = accuracy_score(y_test, kn_pred)
print(kn_acc)
accuracy_list.append(100*kn_acc)
0.8304600531967293
6.梯度增强分类器 Gradient Boosting Classifier
gradientboost_clf = GradientBoostingClassifier(max_depth=2, random_state=1)
gradientboost_clf.fit(X_train,y_train)
gradientboost_pred = gradientboost_clf.predict(X_test)
gradientboost_acc = accuracy_score(y_test, gradientboost_pred)
print(gradientboost_acc)
accuracy_list.append(100*gradientboost_acc)
0.8364693133681411
6.xgbrf分类器 xgbrf classifier
xgb_clf = xgboost.XGBRFClassifier(max_depth=3, random_state=1)
xgb_clf.fit(X_train,y_train)
xgb_pred = xgb_clf.predict(X_test)
xgb_acc = accuracy_score(y_test, xgb_pred)
accuracy_list.append(100*xgb_acc)
print(xgb_acc)
[23:09:17] WARNING: ../src/learner.cc:1061: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'multi:softprob' was changed from 'merror' to 'mlogloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
0.8360752635208354
7.LGBMClassifier
lgb_clf = lightgbm.LGBMClassifier(max_depth=2, random_state=4)
lgb_clf.fit(X_train,y_train)
lgb_pred = lgb_clf.predict(X_test)
lgb_acc = accuracy_score(y_test, lgb_pred)
print(lgb_acc)
accuracy_list.append(100*lgb_acc)
0.8363708009063147
8.Cat Boost Classifier
cat_clf = CatBoostClassifier()
cat_clf.fit(X_train,y_train)
cat_pred = cat_clf.predict(X_test)
cat_acc = accuracy_score(y_test, cat_pred)
print(cat_acc)
accuracy_list.append(100*cat_acc)
990: learn: 0.4190779 total: 12.3s remaining: 112ms
991: learn: 0.4189944 total: 12.3s remaining: 99.5ms
992: learn: 0.4189137 total: 12.3s remaining: 87ms
993: learn: 0.4188195 total: 12.4s remaining: 74.6ms
994: learn: 0.4187774 total: 12.4s remaining: 62.2ms
995: learn: 0.4187095 total: 12.4s remaining: 49.7ms
996: learn: 0.4186093 total: 12.4s remaining: 37.3ms
997: learn: 0.4185544 total: 12.4s remaining: 24.9ms
998: learn: 0.4184855 total: 12.4s remaining: 12.4ms
999: learn: 0.4183650 total: 12.4s remaining: 0us
0.8307555905822086
五、各模型结果对比
print(accuracy_list)
[76.25849669983253, 82.79972416510688, 83.44990641316127, 83.60752635208354, 83.04600531967293, 83.6469313368141, 83.60752635208354, 83.63708009063147, 83.07555905822086]
368141, 83.60752635208354, 83.63708009063147, 83.07555905822086]
model_list = ['DecisionTree', 'RandomForest', 'Logistic Regression', 'SVC','KNearestNeighbours',
'GradientBooster', 'XGBRF','LGBM', 'CatBoostClassifier']
plt.rcParams['figure.figsize']=20,8
sns.set_style('darkgrid')
ax = sns.barplot(x=model_list, y=accuracy_list, palette = "husl", saturation =2.0)
plt.xlabel('Classifier Models', fontsize = 20 )
plt.ylabel('% of Accuracy', fontsize = 20)
plt.title('Accuracy of different Classifier Models', fontsize = 20)
plt.xticks(fontsize = 12, horizontalalignment = 'center', rotation = 8)
plt.yticks(fontsize = 12)
for i in ax.patches:
width, height = i.get_width(), i.get_height()
x, y = i.get_xy()
ax.annotate(f'{round(height,2)}%', (x + width/2, y + height*1.02), ha='center', fontsize = 'x-large')
plt.show()
SVC支持向量机、xgbrf 、lightgbm 耗时特别长,以后不用它!
此文章为搬运
原项目链接
更多推荐
已为社区贡献1438条内容
所有评论(0)