本文数据使用kaggle上的 telco-customer-churn 数据集
分类 | 变量 | 变量名称 | 备注 |
---|---|---|---|
customerID | 客户ID | ||
用户属性 | gender | 性别 | male & female |
用户属性 | SeniorCitizen | 老年用户 | 是为1,否为0 |
用户属性 | Partner | 伴侣用户 | Yes or No |
用户属性 | Dependents | 亲属用户 | Yes or No |
用户属性 | tenure | 在网时长 | 0-72月 |
服务属性 | PhoneService | 是否开通电话服务 | Yes or No |
服务属性 | MultipleLines | 是否有多条线路 | Yes 、No or No phoneservice (无电话服务)三种 |
服务属性 | InternetService | 是否开通互联网服务 | No, DSL数字网络,fiber optic光纤网络 |
服务属性 | OnlineSecurity | 是否开通网络安全服务 | Yes,No,No internetserive(无互联网服务) |
服务属性 | OnlineBackup | 是否开通在线备份服务 | Yes,No,No internetserive(无互联网服务) |
服务属性 | DeviceProtection | 是否开通设备保护服务 | Yes,No,No internetserive(无互联网服务) |
服务属性 | TechSupport | 是否开通技术支持服务 | Yes,No,No internetserive(无互联网服务) |
服务属性 | StreamingTV | 是否开通网络电视 | Yes,No,No internetserive(无互联网服务) |
服务属性 | StreamingMovies | 是否开通网络电影 | Yes,No,No internetserive(无互联网服务) |
合同属性 | Contract | 签订合同方式 | 按月,一年,两年 |
合同属性 | PaperlessBilling | 是否开通电子账单 | Yes or No |
合同属性 | PaymentMethod | 付款方式 | bank transfer银行转账,credit card信用卡,electronic check电子支票,mailed check邮寄支票 |
合同属性 | MonthlyCharges | 月租费 | 18.85-118.35 |
合同属性 | TotalCharges | 累计付费 | 18.85-8684.8 |
合同属性 | Churn | 该用户是否流失 | Yes or No |
library(ggplot2)
library(scales)
library(grid)
library(GGally)
library(rpart)
library(mice)
data <- read.csv("C://Users/dell/Desktop/WA_Fn-UseC_-Telco-Customer-Churn.csv"
,header = T)
attach(data)
class(data)
dim(data)
head(data)
str(data)
#查看缺失值
is.null(data)
md.pattern(data)
#计算缺失值个数占比
na<-is.na(data$TotalCharges)
na[na==FALSE]<-0
na[na==TRUE]<-1
na.rate<-as.numeric(sum(na)/length(na))
na.rate
#剔除缺失值
data<-na.omit(data)
#再次检验是否有缺失值
md.pattern(data)
str(data)#查看数据类型
data$SeniorCitizen[data$SeniorCitizen==0]<-"No"
data$SeniorCitizen[data$SeniorCitizen==1]<-"Yes"
#转换为因子变量
for(i in c(2:5,7:18,21)) {
data[i]<-as.factor(unlist(data[i]))
}
str(data)
for(i in 10:15){
print(xtabs(~ Churn + get(names(data)[i]), data = data))
}
# 将"No internetserive"并入"No"这一属性值
levels(data$OnlineSecurity)[2] <- "No"
levels(data$OnlineBackup)[2] <- "No"
levels(data$DeviceProtection)[2] <- "No"
levels(data$TechSupport)[2] <- "No"
levels(data$StreamingTV)[2] <- "No"
levels(data$StreamingMovies)[2] <- "No"
options(digits=4)
#饼图
ggplot(data, aes(x = "" ,fill = Churn))+
geom_bar(stat = "count", width = 0.5, position = 'stack')+
coord_polar(theta = "y", start=0)+
geom_text(stat="count",
aes(label = scales::percent(..count../nrow(data), 0.01)),
size=4, position=position_stack(vjust = 0.5)) +
theme(
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank()
)
#条形图
ggplot(data , aes(x =Churn , y =..count.. ,fill=Churn)) +
geom_bar(stat = "count", width = 0.5, position = 'identity')
#表格
table(Churn)
用户属性的变量有:gender,SeniorCitizen,Partner,Dependents,tenure
从图中可以得出以下结论:
#用户属性:gender,SeniorCitizen,Partner,Dependents,tenure
library(plyr)
cdata <- ddply(data, "Churn", summarise, tenure.median=median(tenure))
cdata
ggplot(data, aes(x=tenure, fill=Churn)) + geom_density(alpha=.3)+
geom_vline(data=cdata, aes(xintercept=tenure.median, colour=Churn),
linetype="dashed", size=1)
Percentage<- matrix(rep(1,nrow(data)),nrow=(nrow(data)),ncol=1)
plot1<-ggplot(data, aes(x=gender, y=Percentage, fill=Churn))+geom_col(position="fill")
plot2<-ggplot(data, aes(x=SeniorCitizen, y=Percentage, fill=Churn))+geom_col(position="fill")
plot3<-ggplot(data, aes(x=Partner, y=Percentage, fill=Churn))+geom_col(position="fill")
plot4<-ggplot(data, aes(x=Dependents, y=Percentage, fill=Churn))+geom_col(position="fill")
grid.newpage()
pushViewport(viewport(layout = grid.layout(2,2)))
vplayout <- function(x,y)
viewport(layout.pos.row = x, layout.pos.col = y)
print(plot1, vp = vplayout(1, 1))
print(plot2, vp = vplayout(1, 2))
print(plot3, vp = vplayout(2, 1))
print(plot4, vp = vplayout(2, 2))
服务属性的变量有:
PhoneService, MultipleLines, InternetService, OnlineSecurity, OnlineBackup, DeviceProtection,
TechSupport, StreamingTV, StreamingMovies
从图中可以得出以下结论:
#服务属性:PhoneService,MultipleLines,InternetService,OnlineSecurity,OnlineBackup,
#DeviceProtection,TechSupport,StreamingTV,StreamingMovies
#流失率对比
plot4<-ggplot(data, aes(x=PhoneService, y=Percentage, fill=Churn))+geom_col(position="fill")
plot5<-ggplot(data, aes(x=MultipleLines, y=Percentage, fill=Churn))+geom_col(position="fill")
plot6<-ggplot(data, aes(x=InternetService, y=Percentage, fill=Churn))+geom_col(position="fill")
plot7<-ggplot(data, aes(x=OnlineSecurity, y=Percentage, fill=Churn))+geom_col(position="fill")
plot8<-ggplot(data, aes(x=OnlineBackup, y=Percentage, fill=Churn))+geom_col(position="fill")
plot9<-ggplot(data, aes(x=DeviceProtection, y=Percentage, fill=Churn))+geom_col(position="fill")
plot10<-ggplot(data, aes(x=TechSupport, y=Percentage, fill=Churn))+geom_col(position="fill")
plot11<-ggplot(data, aes(x=StreamingTV, y=Percentage, fill=Churn))+geom_col(position="fill")
plot12<-ggplot(data, aes(x=StreamingMovies, y=Percentage, fill=Churn))+geom_col(position="fill")
grid.newpage()
# pushViewport函数提供了添加视图以及在树中的视图之间导航的方法。
pushViewport(viewport(layout = grid.layout(3,3)))
# viewport函数创建视图,描述图形设备上的矩形区域,并在这些区域中定义许多坐标系统。
vplayout <- function(x,y)
viewport(layout.pos.row = x, layout.pos.col = y)
print(plot4, vp = vplayout(1, 1))
print(plot5, vp = vplayout(1, 2))
print(plot6, vp = vplayout(1, 3))
print(plot7, vp = vplayout(2, 1))
print(plot8, vp = vplayout(2, 2))
print(plot9, vp = vplayout(2, 3))
print(plot10, vp = vplayout(3, 1))
print(plot11, vp = vplayout(3, 2))
print(plot12, vp = vplayout(3, 3))
合同属性的变量有:
MonthlyCharges,TotalCharges,Contract,PaperlessBilling,PaymentMethod
从图中可以得出以下结论:
#合同属性:MonthlyCharges,TotalCharges,Contract,PaperlessBilling,PaymentMethod
#流失率对比
cdata1 <- ddply(data, "Churn", summarise, MonthlyCharges.median=median(MonthlyCharges))
cdata2 <- ddply(data, "Churn", summarise, TotalCharges.median=median(TotalCharges))
plot13<-ggplot(data, aes(x=MonthlyCharges, fill=Churn)) + geom_density(alpha=.3)+
geom_vline(data=cdata1, aes(xintercept=MonthlyCharges.median, colour=Churn),
linetype="dashed", size=1)
plot14<-ggplot(data, aes(x=TotalCharges, fill=Churn)) + geom_density(alpha=.3)+
geom_vline(data=cdata2, aes(xintercept=TotalCharges.median, colour=Churn),
linetype="dashed", size=1)
plot15<-ggplot(data, aes(x=Contract, y=Percentage, fill=Churn))+geom_col(position="fill")
plot16<-ggplot(data, aes(x=PaperlessBilling, y=Percentage, fill=Churn))+geom_col(position="fill")
plot17<-ggplot(data, aes(x=PaymentMethod, y=Percentage, fill=Churn))+geom_col(position="fill")
grid.newpage()
# pushViewport函数提供了添加视图以及在树中的视图之间导航的方法。
pushViewport(viewport(layout = grid.layout(1,2)))
# viewport函数创建视图,描述图形设备上的矩形区域,并在这些区域中定义许多坐标系统。
vplayout <- function(x,y)
viewport(layout.pos.row = x, layout.pos.col = y)
print(plot13, vp = vplayout(1, 1))
print(plot14, vp = vplayout(1, 2))
grid.newpage()
# pushViewport函数提供了添加视图以及在树中的视图之间导航的方法。
pushViewport(viewport(layout = grid.layout(3,1)))
# viewport函数创建视图,描述图形设备上的矩形区域,并在这些区域中定义许多坐标系统。
vplayout <- function(x,y)
viewport(layout.pos.row = x, layout.pos.col = y)
print(plot15, vp = vplayout(1, 1))
print(plot16, vp = vplayout(2, 1))
print(plot17, vp = vplayout(3, 1))
#相关性分析:1.分类变量2.连续变量
#1.分类变量
myFUN<- function(x){chisq.test(data$Churn,x ,correct = TRUE)}
#apply(数据库,循环数据库3到6列,按列,函数)
colnames(data)
xx = c("customerID","tenure","MonthlyCharges","TotalCharges")
dataset = data[,!names(data) %in% xx]
result<- apply (dataset,2, myFUN)
#创建功能,提取list每个循环的p.value
p<- function(x){x$p.value}
#转化成数据,sapple(数据框,函数)
p2<-as.data.frame(sapply(result,p))
#保留小数点后面3位小数
result=as.data.frame(round(p2$`sapply(result, p)`,3))
#添加比较组的行名
A<-names(dataset)
A
rownames(result)=A
result
#2.连续变量
ggpairs(data,columns=c(6,19:20),ggplot2::aes(color=data$Churn))
#3.去掉不相关变量
xx = c("customerID","gender","TotalCharges")
data1 = data[,!names(data) %in% xx]
head(data1)
#划分训练集和测试集
set.seed(1234) #随机抽样设置种子
train<-sample(nrow(data),0.7*nrow(data)) #抽样函数,第一个参数为向量,nrow()返回行数 后面的是抽样参数前
tdata<-data1[train,] #训练数据集
vdata<-data1[-train,] #测试数据集
算法 | 区分要点 | R包 |
---|---|---|
ID3 | 使用信息增益 | rpart包中rpart函数 |
C4.5 | 使用信息增益 | RWeka包中J48() |
CART | 使用gini | rpart包中rpart函数 |
C5.0 | C4.5的改进,比较适合于大规模数据 | c50包 |
#CART
dtree<-rpart(Churn~.,data=tdata,method="class",parms=list(split="gini"))#运用二分类决策树CART算法
printcp(dtree)#查看cp参数复杂度,cp越大数分裂规模越小
tree<-prune(dtree,cp=dtree$cptable[which.min(dtree$cptable[,"xerror"]),"CP"])#剪枝,自动选择最小exerror的cp值来剪枝
opar<-par(no.readonly = T)
par(mfrow=c(1,2))
library(rpart.plot)
png(file = "G://R/tree1.png")
rpart.plot(dtree,branch=1,type=2, fallen.leaves=T,cex=0.8, sub="剪枝前")
png(file = "G://R/tree2.png")
rpart.plot(tree,branch=1, type=4,fallen.leaves=T,cex=0.8, sub="剪枝后")
par(opar)
dev.off()
predtree<-predict(tree,newdata=vdata,type="class") #利用预测集进行预测
table(vdata$Churn,predtree,dnn=c("真实值","预测值")) #输出混淆矩阵
本文参考了以下文章
- R语言相关性分析和相关性分析可视化常用方法汇总
- R语言_电信客户流失数据分析
- ggplot2一页多图的实现方法
- 数据分析中缺失值处理~R语言
- ggplot2-堆积柱形图
- 【数据分析与挖掘实战】