首页 > > > 【R语言】:简单数据处理分析
《从零学会数据分析:简单数据处理》学习笔记
本文代码运行环境为Windows版RStudio
一、XLConnect
以前专门介绍过,详见【R语言】:导入Excel数据
二、openxlsx
使用openxlsx比较适合于读取Excel数据量比较大的情况,如果使用XLConnect可能会出现内存溢出(指程序在申请内存时,没有足够的内存空间供其使用,out of memory)的情况。
以课程中提供的数据“朝阳医院2016年销售数据”为例,首先安装openxlsx包。



据说,数据分析师多达60%的工作时间都用在实际开始之前的数据准备工作中,比如处理缺失的数据、改变列名、处理时间格式的数据等,即数据预处理。
数据预处理的目标是把原始数据改变成自己便于处理的格式,或者说使原始数据符合自己接下来进行数据分析的需求,类似于发朋友圈之前用修图软件PS原始照片。
原来Excel表格读取到R语言之后的列名仍然为为中文,如下图

为了便于之后使用R语言处理数据(编程语言是英文),需要将数据框中的中文列名全部转换为英文,即对列名重新命名。
一般使用函数names()重命名列名,代码如下
names(exceldata) <- c("Time", "CardNum", "DrugID", "DrugName", "SaleNum", "Receivables", "Proceeds")
二、数据不完整
任何原始数据都有可能因为各种情况造成某些字段的数据不完整,所以在实际工作中需要删除不完整的数据,在R语言中缺失值用NA表示。
之前载入的“朝阳医院2016年销售数据”,购药时间为空是无法接受的,可以通过逻辑运算符、函数is.na()删除数据中为空的行。
函数is.na()表示为空的数据,逻辑运算符!表示“非”的含义,$Time表示仅选取Time这一列中非空的数据。为了跟原有数据框区分,这里将选取的数据全部存到新的数据框salesdata中(直接覆盖原有数据框exceldata也可以)。代码如下:

此外,还可以用函数na.omit()删除所有包含缺失数据的行。
关于逻辑运算符、函数is.na()和函数na.omit()更详尽的用法和实例可参考【R语言】:基本数据管理(1)中有关缺失值的相关内容。
三、处理日期
数据框中Time这一列的数据类型是字符串,包含的内容是日期+空格+星期几,而实际上只需要提取日期,所以问题便转化为如何将字符串的数据分拆出数据处理所需要的部分字符串?即只保留原字符串的一部分内容,即日期。具体方法如下:

1、stringr包和函数str_split_fixed()
课程中提到分拆字符串可以利用stringr包,首先来安装

Google了一下用stringr包应该用什么函数来拆分字符串,结果是函数str_split_fixed()。
2、载入stringr包,利用函数help()查询函数str_split_fixed()的用法(或者继续Google该函数的用法)

3、实现“拆分数据框salesdata中Time这一列的数据,以空格未拆分标准,拆分成两列”的代码如下:
timesplit <- str_split_fixed(salesdata$Time, " ", n=2)
运行代码后,得到包含两列的数据框timesplit

salesdata$Time <- timesplit[, 1]运行代码,得到只保留日期的数据框salesdata

数据类型的判断和转换,在【R语言】:基本数据管理(2)中提到过:is开头表示判断,as开头表示转换。

1、字符串格式转换为日期格式
函数class()查看数据格式


2、字符串格式转换为数值格式
数值格式适用于之后的数据分析中相关计算,利用函数as.numeric()转换。

五、数据排序
数据排序能让数据分析人员发现更多有价值的信息,利用函数order()来实现,详见R语言】:基本数据管理(2)。
如果按照销售时间升序排列,可输入以下代码
#销售时间升序排列,方法一
salesdata <- salesdata[order(salesdata$Time, decreasing = FALSE), ]
#销售时间升序排列,方法二
salesdata <- salesdata[order(salesdata$Time), ]运行代码后,见下图

六、数据预处理步骤总结
第一步,重命名列明,便于之后写代码;
第二步,删除缺失数据,保证数据完整性;
第三步,处理日期,拆分字符串;
第四步,数据类型转换,便于之后分析计算;
第五步,数据排序,发现可能更多有价值的信息。
原始数据经过预处理之后就可以根据业务需要进行业务指标分析了。
一、月均消费次数
月均消费次数=总消费次数/月份数
1、总消费次数
其中,根据业务部门提供的信息,总消费次数的含义是同一天内,同一个人发生的所有消费算作一次消费。因此,在数据框salesdata中Time(销售时间)和CardNum(社保卡号)完全相同的数据只需要保留一条。


#salesdata[, c("Time", "CardNum")]表示选出数据框salesdata中Time和CardNum两列
#利用函数duplicated将数据框中重复的数据标记为TRUE,不重复的数据标记为FALSE
#在函数duplicated前加逻辑运算符!将数据框中不重复数据的标记转换为TRUE
#以此建立一个是否重复的索引index_KPI1
index_KPI1 <- !duplicated(salesdata[, c("Time", "CardNum")])
#依据索引index_KPI1删除数据框中重复的数据,并将结果赋值给变量KPI_1
KPI_1 <- salesdata[index_KPI1,]
#将以上步骤合起来代码如下
KPI_1 <- salesdata[!duplicated(salesdata[, c("Time", "CardNum")]),]
那么,总消费次数就是数据框KPI_1的总观测数(行数),代码如下
consum_num <- nrow(KPI_1)
2、月份数
首先确定数据框KPI_1中的时间范围,由于之前已经按照销售时间升序排列,所以最早时间是Time这一列中的第一条数据,最晚时间是该列最后一条数据。总天数就是最晚时间减去最早时间,总月数用逻辑运算符整数除法(%/%)可得。
#最早时间
startTime <- KPI_1$Time[1]
#最晚时间,下标用总观测数来确定
end_time <- KPI_1$Time[nrow(KPI_1)]
#总天数
days <- end_time - start_time
#总月数,逻辑运算符%/%表示整数除法
months<- days %/% 30
运行代码后,最后一句报错

#总月数,逻辑运算符%/%表示整数除法
months<- as.numeric(days) %/% 30
运行后没问题,于是月均消费次数=总消费次数/月份数
#同样取整数
consume_month_num <- consum_num %/% months
二、月均消费金额
月均消费金额=总消费金额/月份数
月份数之前已经算出来了,接下来只需要计算总消费金额,使用函数sum()。

#总消费金额为实收金额总和
money_total <- sum(salesdata$Proceeds, na.rm = TRUE)
#月均消费金额=总消费金额/月份数
money_month <- money_total / months
三、客单价
客单价=总消费金额/总消费次数
客单价(Per Customer Transaction,PCT)就是每个人消费的单价,总消费金额和总消费次数已经得到,直接计算即可。
PCT <- money_total / consum_num四、消费趋势
消费趋势是指消费金额随着时间变化而变化的趋势,时间能够以年、月、周、日、小时等时间段来划分,实际中主要是根据业务部门的需要确定,这里按照每周为时间间隔所呈现的消费趋势为例。
目前数据框中的数据是每天的消费金额,按周呈现消费趋势就必须计算出每周的消费金额。因此,任务目标被分解为:第一,把原始数据按照“周”分组;第二,计算按“周”分组之后的每周的消费金额;第三,根据新分组生成的数据画图得出消费趋势。
1、函数tapply()
R语言中有一类函数叫apply函数家族,包括apply、sapply、tapply、mapply、lapply、rapply、vapply、eapply等,这里主要介绍如何利用分组函数tapply()来实现目标。

tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
参数含义
- X:向量
- INDEX:用于分组的索引(按照什么条件进行分组)
- FUN:自定义的调用函数
- …:接收多个数据
- simplify:是否数组化,当值array时,输出结果按数组进行分组
因此,函数tapply()用于分组的循环计算,通过INDEX参数可以把数据集X进行分组,再通过FUN参数对分组后的数据求和。具体代码如下:
week_consume <- tapply(salesdata$Proceeds, format(salesdata$Time, "%Y-%U"), sum)第一个参数表示数据框salesdata中的实收金额(Proceeds列);第二个参数表示按照什么条件进行分组,实际目标是按照“年-周”分组,因此这里需嵌套另外一个函数format(),该函数可以将时间格式调节成指定时间样式(%Y-%U,更多时间样式的规则请查看函数format()参数的格式和涵义);第三个参数表示将对分组后数据用求和函数sum()进行计算,并返回二维数组(即每一周的序号和每一周的消费总金额)。
2、绘制消费曲线图
首先,将输出的二维数组转化为表。
week_consume <- as.data.frame.table(week_consume)其次,重新定义表的列名
names(week_consume) <- c("Time","Proceeds")
接着,判断表里两个列向量的数据类型
> class(week_consume$Time)
[1] "factor"
> class(week_consume$Proceeds)
[1] "numeric"第四步,把因子转换为字符串
week_consume$Time <- as.character(week_consume$Time)第五步,增加一列TimeNum用于绘图时的x轴数据
week_consume$TimeNum <- c(1:nrow(week_consume))
第六步,利用函数plot()和函数axis()绘制销售趋势图形,具体可参考【R语言】:图形初阶(1) 、【R语言】:图形初阶(2)、【R语言】:图形初阶(3)。
plot(week_consume$TimeNum, week_consume$Proceeds, xlab = "时间(年份-周)", ylab = "消费金额", xaxt = "n", main = "2016年朝阳医院消费曲线", col = "blue", type = "b")
axis(1, at = week_consume$TimeNum, labels = week_consume$Time, cex.axis = 1.5)
运行代码之后,得到下图

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3159871/ ,如需转载,请注明出处,否则将追究法律责任。