一、基于人工智能的校园霸凌受害者预测与分析
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()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
序号 | 过去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()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
序号 | 过去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()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
序号 | 过去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()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
序号 | 过去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)