我导因为疫情等原因,今年的授课的凝聚态物理是在网上完成的。
在师兄统计完上课的时长信息的细碎文件之后,我秉着好奇的态度,对数据进行了一个简单的可视化分析,先做了一个条形统计图和按照时长从长到短的排序沿x轴绘制散点图。
汇总好的文件(out_(2).csv)的最后一列是处理好的总时长。
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
cd = pd.read_csv("./out_(2).csv")
tm = cd.iloc[:,-1]
plt.hist(tm,bins =4)
plt.show()
可以看到,如果bins的个数选为4,6000~100000大致在一个bins里,并且这个bins的旁边占得比例是比较少的。
此外注意到,0~20000的比率也不小,这点我解释一下,主要是游客(比如我,看了十几分钟因为有(fan)事(kun),并且也没选这个课,就溜了,由此看来,老板名声显赫,慕名而来的游客不少)
import numpy as np
X = np.linspace(0,100,len(tm))
plt.scatter(X,tm)
plt.grid()#打开坐标网格
plt.xlabel("id")
plt.ylabel("time(s)")
plt.axhline(y=96273+7200,ls=":",c="red")#老板的上课时间+2小时
plt.axhline(y=96273,ls=":",c="yellow")#老板的在线时长
plt.axhline(y=40000,ls=":",c="red")#按照每节课就一个小时计算的上课时间
y1 = 40000
y2 = 96273+7200
plt.fill_between(X, y1, y2, facecolor='green', alpha=0.3)
plt.show()
在这里要说明一下,有部分人上课的时候换过网名,导致他的数据是两个加在一起的,这些数据需要在整理统计,但这部分人属于少数,因此先分析大多数人。
这个图中的黄色虚线是任课老师的在线时间,其余时间也是尽量放宽了。
上红线为老板的上课时间+2小时,主要应对有学生提前等待上课,给两个小时的缓冲总是够了吧。
下红线为按照每节课就1小时,大致给出的时间区间,这个区间主要是把一些迟到了但是也来了的人考虑进来了,并且有两个账号的人也应该在这个区间内。
我们可以看出来这条曲线在80000~100000的表征是一条光滑的曲线,可以认为这些人是正儿八经上课的好学生,不换名字,上课时间基本符合要求。
8000~4000是情况有点情况的学生,不管是迟到还是请假,如果不是双账号的人应该有请假记录之类的,老板那里有记录才对。
2000~0 游客,不分析,来去自由。
130000~103,473 就开始离谱了,最多的一个比任课老师在线时长最多的多了接近10个小时,分析最高的那个市场,回查小时间,发现有一节课是从5点到8点半,她上课时间为1点到10点啊这不就是吃完午饭就出去玩了呗…
或许她其他时间都是ok的呢?只是这一次离域了呢?于是我把每次的在线时长作为特征,截取在总值80000之前的数据,使用机器学习的一些方法来做异常值检测。
emmmm
再做一个箱型图检测吧,万一曲线表现不出一些性质呢,于是乎:
import pandas as pd
import matplotlib.pyplot as plt
data = pd.DataFrame(y)
plt.rcParams['font.sans-serif'] = ['SimHei'] #指定字体为黑体
plt.rcParams['axes.unicode_minus'] = False #显示负号
plt.figure()
p = data.boxplot(return_type='dict') #画箱式图
x = p['fliers'][0].get_xdata() #fliers为异常值标签,get_xdata()与get_ydata()用来获取横纵坐标数组
y = p['fliers'][0].get_ydata()
y.sort()
#使用annotate添加注释,xy表示标注点坐标, xytext表示注释坐标
for i in range(len(x)):
if i > 0:
plt.annotate(y[i], xy=(x[i], y[i]), xytext=(x[i]+0.05 - 0.8/(y[i]-y[i-1]), y[i]))
else:
plt.annotate(y[i], xy=(x[i], y[i]), xytext=(x[i]+0.08, y[i]))
plt.show()
接下来做一个主成分分析,数据染色根据依然是总时长,看看小时间段的分布特点和别的数据是否可以聚类。
x = cd.iloc[:,1:-1]
y = cd.iloc[:,-1]
#ax = plt.axes(projection='3d')
newdf = np.array(y)
close = newdf
volume = newdf
from sklearn.decomposition import PCA
#ax = plt.axes(projection='3d')
pca = PCA(n_components=2)
pca.fit(x)
x_pca = pca.transform(x)
import seaborn as sns
from matplotlib import pyplot as plt
plt.figure(figsize=(10,5))
plt.scatter(x_pca[:, 0], x_pca[:, 1], alpha=0.8 ,c =close)
#ax.scatter3D(x_pca[:, 0], x_pca[:, 1], x_pca[:, 2], c=close)
plt.colorbar()
plt.savefig("PCA.png",dpi=300,bbox_inches="tight")
plt.show()
额。。。。
可以发现有两个数据点是离域了,然而,那个人依然,离域。这说明他的上课习惯和别人的确不一样,也因此可以推断:红线上方的那些上课时间很长的人,可能是习惯提前半个小时准备上课的,或者下课写好笔记等一定时间离开,总之,是和其他人有规律可循的,数据的特征是相似的。
因此我回代数据,发现坐标(0,19000)的那个人是因为有两个账号,名字不一样的两个账号,因此不符合规律。而坐标(40000,-2000)处的那个离域,似乎是实锤了与他人上课规律的确不一致,而不是偶尔一次怎么怎么的。---------------------------------------------------------------
写到这里,我还是想尽力给他洗白,因此我再使用数据异常检测的杀招:孤立森林方法检测
from sklearn.model_selection import train_test_split
from sklearn.ensemble import IsolationForest
clf=IsolationForest(behaviour='new',max_samples=100,contamination='auto')
x = cd.iloc[:,1:-1]
y = cd.iloc[:,-1]
X_train,X_test,y_train,y_test =train_test_split(x,y,test_size=0.2)
outliers_fraction =0.01
from scipy import stats
clf = IsolationForest(max_samples=66)
clf.fit(X_train)
scores_pred = clf.decision_function(X_train)
threshold = stats.scoreatpercentile(scores_pred, 100 * outliers_fraction)
print(clf.predict(x))
可以通过调整outliers_fraction =0.01 来选择异常值的比率为多少
[-1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 -1 1 1
1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1]
在此我甚至后面又用了20折交叉验证这个预测结果
他均为异常值
好吧,你平时分没了,虽然你刷的时间的确很长…
------------------END------------------