泰迪杯特等奖思路(教育平台线上课程⽤户⾏为分析(含数据
可视化处理))-代码篇
此数据集与题⽬来⾃于2020年泰迪杯个⼈技能赛,为某线上平台真实数据。该作品已获得同年最好成绩,为特等奖并获泰迪杯,现在⽬前的基础之上对其进⾏进⼀步的复盘与优化,如果⼤家有更好的想法或者思路也可以给我评论,⼤家⼀起交流进步呀!
import pandas as pd
import numpy as np
import datetime
import jieba
import matplotlib
import matplotlib.pyplot as plt
from chinese_calendar import is_workday
from pyecharts import Bar
1.1缺失值处理
⾸先判断该缺失值是否为真实缺失。针对不同的数据缺失情况,本次分析将会采⽤不同的处理⽅式:
1、针对数值为 0 的情况,需要进⾏实际的分析,回归到原始数据中去,判断该数据为 0 时是否具有实际意义。如果没有就将其作为
缺失值做删除处理
2、针对数据为空值的情况,如果该特征数据缺失情况低于 10%,则结合该特征的重要性进⾏综合判断。如果字段重要性较低,则考虑
直接删除,如果字段重要性较⾼,则进⾏插值法或者采⽤数据均值进⾏填补
ad_csv('login.csv',encoding='gbk')
login.info()
# 没有缺失值
1.2重复值处理
在完成缺失数据和异常数据处理之后,对数据进⾏重复值的删除处理。此处的重复值是指在数据表中⽤于分析的各个字段均⼀致。
#⼀天内重复登录的⾏为我们将视为⼀次登录即可,以减少数据量
# ⽅法⼀
# data1=login['login_time'].str.split(' ',expand=True)[0]
# at([login,data1],axis=1)
# ame(columns={0:'⽇期'},inplace=True)
# del login['login_time']
# login
# ⽅法⼆
def str_datetime(df,column_name='login_time'):
df[column_name]=pd.to_datetime(df[column_name])
df[column_name]=df[column_name].apply(lambda x:x.strftime('%Y-%m-%d'))
return df
login=str_datetime(login)
# 将同⼀⽇期⽤户重复登陆⾏为删除
login=login.drop_duplicates()
login
# 以最近的时间为基准,计算出⽤户每⼀次登录距离现在的时间
# 以最近的时间为基准,计算出⽤户每⼀次登录距离现在的时间
login['时间差1']=pd.to_datetime(login['login_time']).max()-pd.to_datetime(login['login_time']) login
# 重新排序
set_index()
del login['index']
# # 地区拆分
# # 运⾏时间很长-⽽且切词并不准确,很多没有切除⼲净
# for i in range(login.shape[0]):
# li=[str(i.word) for i wSegment("crf").seg(login.iloc[i,2])]
# # li=[word for word in jieba.cut(login.iloc[i,2])]
# if len(li)==1:
# if '中国' in login.iloc[i,2]:
# login.loc[i,'国家']=login.iloc[i,2][0:2]
# login.loc[i,'省份']=login.iloc[i,2][2:]
# else:
# login.loc[i,'国家']=login.iloc[i,2]
# elif len(li)==2:
# login.loc[i,'国家']=li[0]
# login.loc[i,'省份']=li[1]
# else:
# login.loc[i,'国家']=li[0]
# login.loc[i,'省份']=li[1]
# login.loc[i,'地区']=li[2]
# if i % 10000 ==0:
# print(i)
# 改进版本
for i in range(login.shape[0]):
if login.loc[i,'login_place'][0:2]=='中国':
login.loc[i,'国家']='中国'
if '⿊龙江' in login.loc[i,'login_place']:
login.loc[i,'省份']='⿊龙江'
if len(login.loc[i,'login_place'])>5:
login.loc[i,'地区']=login.loc[i,'login_place'][5:]
else:pass
if '新疆维吾尔' in login.loc[i,'login_place']:
login.loc[i,'省份']='新疆维吾尔'
if len(login.loc[i,'login_place'])>7:
login.loc[i,'地区']=login.loc[i,'login_place'][7:]
else:pass
if '内蒙古' in login.loc[i,'login_place']:
login.loc[i,'省份']='内蒙古'
if len(login.loc[i,'login_place'])>5:
login.loc[i,'地区']=login.loc[i,'login_place'][5:]
else:pass
else:
login.loc[i,'省份']=login.loc[i,'login_place'][2:4]
login.loc[i,'地区']=login.loc[i,'login_place'][4:]
else:
li=[word for word in jieba.cut(login.iloc[i,2])]
if len(li)==2:
login.loc[i,'国家']=li[0]
login.loc[i,'省份']=li[1]
else:
login.loc[i,'国家']=li[0]
if i%10000==0:
print(f'{round(i*100/(int(login.shape[0])),2)}%')
# 重新读取已经切分好城市的数据
login =pd.read_excel('⽤户地区切割.xlsx',index_col=0)
stu_ad_csv('study_information.csv',encoding='gbk')
stu_info=stu_info.drop_duplicates()
stu_info.info()
#没有完全重复数据,但是存在价格缺失数据
stu_info[stu_info.price.isnull()].course_id.value_counts()
stu_course=upby(['course_id']).agg({'price':['max','min']})
stu_course[(stu_course['price']['max']-stu_course['price']['min'])!=0]
#不存在差异定价,且51和96课程价格为nan,其中51和96课程共计4238条数据,暂时不做处理
# 将进度转化成为数值型,从⽽便于计算
stu_info['learn_process']=stu_info['learn_process'].apply(lambda x:int(x.split('width:')[-1].split('%')[0]))
# 对加⼊时间进⾏相同操作
stu_info=str_datetime(stu_info,column_name='course_join_time')
stu_info
ad_csv('users.csv',encoding='gbk')
考虑到⽤户ID是⽤户的唯⼀标识,确实为缺失情况,⽽⾮正常可不填选项,且缺失的数据相对较少,因此删除数据学校数据字段缺失严重,考虑为实际选填数据,暂时保留,并且创建是否填写学校信息
users=users[~users.user_id.isnull()]
# 将是否填写学校信息设置成为0、1变量,作为后续可能有⽤的信息
users['是否填写学校信息']=users['school']
users.是否填写学校信息[~users['是否填写学校信息'].isnull()]=1
users.是否填写学校信息[users['是否填写学校信息'].isnull()]=0
users.是否填写学校信息.value_counts()
1.3异常值处理
可以看出有⼀些recently_logged时间和现在的时间很接近,有⼀些很远,因此可以将‘--’进⾏进⼀步分析⽤户注册后未登录
⽤户注册后就未退出登录 使⽤login中的最新登录信息进⾏替换
因此考虑使⽤学习时间加上注册的时间作为其最近的登录时间,且设置⼀天学习8⼩时为上限
excel线上教学课程upby('user_id').login_time.max().list()
upby('user_id').login_time.max().list()
login_time={}
for i in range(len(keys)):
login_time[keys[i]]=values[i]
u_2=ly_logged!='--']
u_1=ly_logged=='--']
for i in range(u_1.shape[0]):
if u_1.iloc[i,0] in login_time.keys():
u_1.iloc[i,2]=pd.to_datetime(login_time[u_1.iloc[i,0]])
else:
_datetime(u_1.iloc[i,1])+datetime.timedelta(days = int(u_1.iloc[i,5])/480 )&_datetime('2020-06-18'):
u_1.iloc[i,2]=pd.to_datetime('2020-06-18')
print('修改时间为最新时间')
else:
u_1.iloc[i,2]=pd.to_datetime(u_1.iloc[i,1])+datetime.timedelta(days = int(u_1.iloc[i,5])/480 )
at([u_1,u_2])
# 还是以最近的时间为基准,计算出⽤户登陆注册⾏为的时间差
str_datetime(users,column_name='register_time')
str_datetime(users,column_name='recently_logged')
users['register_logged_time']=pd.to_datetime(users['recently_logged'])-pd.to_datetime(users['register_time'])
users['register_now_time']=pd.to_datetime(users['register_time']).max()-pd.to_datetime(users['register_time'])
users['logged_now_time']=pd.to_datetime(users['recently_logged']).max()-pd.to_datetime(users['register_time'])
users
# 现在加⼊的班级的数量
users['number_of_classes_now']=users['number_of_classes_join']-users['number_of_classes_out']
users
信息整合
计算选课数量
def nx_data(df=stu_info,group_name=['course_id','user_id']):
# 得到共现字典
user_dic={}
stu_info_upby(group_name)['course_id'].count().unstack()
column=stu_list()
for i in range(stu_info_data.shape[0]):
user_dic[column[i]]=stu_info_data[stu_info_data[column[i]]==1].list()
#构造共现矩阵
course_name=list(set(df['course_id'].list()))
course_data=pd.DataFrame(s(shape=(len(course_name),len(course_name))),index=course_name,columns=course_name) for value in user_dic.values():
if len(value)==1:
pass
else:
for i in range(len(value)):
for j in range(i+1,len(value)):
course_data.loc[value[i],value[j]]+=1
return (user_dic,course_data)
user_dic,course_data=nx_data()
for i,key in enumerate(user_dic.keys()):
users.loc[i,'选课数量']=len(user_dic[key])
users
地区合并
取最近的登录地点合并
# ad_excel('⽤户地区切割.xlsx',index_col=0)
login_1=login.sort_values(by=['user_id','时间差1'])
login_del=login_1.user_id.drop_duplicates()
login_diff=login.iloc[list(login_del.index),:]
users_(users,login_diff,how='left')
_excel('全部信息.xlsx')
users_all=set_index()
users_all=users_all.drop(columns=['index'])
users_all
2.1⽤户分布分析
2.1.1海内外分布
country=login[login['国家']!='中国'].国家.value_counts().list()
country_count=login[login['国家']!='中国'].国家.value_counts().list()
login.国家.value_counts()
from pyecharts import Line, Pie, Grid
line=Line()
line.add( "",country,country_count,mark_point=["max", "min"],mark_line=["average"])
pie = Pie("", title_pos="55%")
pie.add( "", country, country_count, radius=[45, 65],center=[74, 50],legend_pos="80%",legend_orient="vertical",rosetype="radius",is_legend_show=False,is_label
grid = Grid(width=900)
grid.add(line, grid_right="55%")
grid.add(pie, grid_left="50%")
grid
2.1.2中国省份分布
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论