初试数据分析(R)

浏览: 993

这篇的文章主要目的是,根据提供的朝阳区医院2016年销售数据.xlsx数据表,得出月均消费次数、月均消费金额、客单价和消费趋势这五个结论。

阅读路线:

  • 数据导入
  • 数据清洗
  • 数据分析

数据导入

为了方便,我把excel文件另存为了csv文件,并且重命名为2016.csv,然后放在Desktop文件夹下。

设置工作路径

>setwd("C:\\Users\\lkx\\Desktop")

查看下到底是不是这个工作路径

>getwd()
[1"C:/Users/lkx/Desktop"   #确实是的

利用read.table()读入csv文件

> import.csv<-read.table("2016.csv",header = TRUE,sep=",")
 # 其中"2016.csv"就是我们要读入的文件;header=TRUE表示读入变量(就是我们excel中见到的表头);sep=","表示以逗号为分隔符

我们读取前六行先简单看一下数据

head(import.csv)
           购药时间    社保卡号 商品编码   商品名称 销售数量 应收金额 实收金额
1 2016-01-01 星期五     1616528   236701 三九感冒灵        7      196   182.00
2 2016-01-02 星期六     1616528   236701 三九感冒灵        3       84    84.00
3 2016-01-06 星期三 10070343428   236701 三九感冒灵        3       84    73.92
4 2016-01-11 星期一    13389528   236701 三九感冒灵        1       28    28.00
5 2016-01-15 星期五   101554328   236701 三九感冒灵        8      224   208.00
6 2016-01-20 星期三    13389528   236701 三九感冒灵        1       28    28.00

其实我们读入的数据共有6577行,7列

如果点击上图中箭头所指向的位置就能够看到所有的数据:

数据处理

当我们拿到数据的时候不应该着急去计算,先观察数据,看数据是否规整、是否符合我们的需要。根据我们的分析要求将做五个方面的修整:列名重命名、删除缺失数据、处理日期、数据类型转换和数据排序

  • 列名重命名

把列名汉语名称变为英文状态下的名称将会编程环境更加适合。这里我们通过names()函数来重命名变量。

>names(import.csv)<- c("time","cardno","drugld","drugName","saleNumber","virtualmoney","actualmoney")
  • 删除缺失数据

在任何规模的项目中,数据都可能由于未作答问题、设备故障或误编码数据的缘故而不完整。缺失值以符号NA(Not Available,不可用)表示。函数is.na()检测缺失值是否存在的
举例子:

> y<-c(1,2,3,NA)
> is.na(y)
[1FALSE FALSE FALSE  TRUE

注意:

  1. is.na()函数是如何作用于一个对象上的,它将返回一个相同大小的对象,如果某个元素是缺失值,相应的位置将被改写为TRUE,不是缺失值的位置则为FALSE。
  2. 但是我们也应该注意到那些因为未作答问题、设备故障或错误编码数据得来的数据,不一定都是用NA来表示的,比如说因为错误得到的正无穷或负无穷都是Inf或-Inf来表示的,就需要用is.infinite()来检测了。
  3. 再者说,对于数据中某些特别怪异的值,比说在这个数据框变量销售数量中有一个值为100000000,我们看到这样的值与其他的差别如此之大,我们就可以重编码这个值为缺失值

所以接下来我们做的处理是:

import.csv<-import.csv[!is.na(import.csv$time),]
#import.cav$time  表示选取time这一列
#is.na(import.csv$time)返回一个和import.csvs$time相同大小的对象,如果元素是缺失值,相应的位置将被改写为TRUE,不是缺失值的位置则为FASLE
#'!'是非的意思,!is.na(import.csv$time)将和is.na(import.csv$time)是完全相反的结果
#import.csv[!is.na(import.csv$time),]表示只要time这一列中判断条件为TRUE的对象;也即是意味着,删除time列中为缺失值的所有行。

其实,我们还可以通过函数na.omit()移除所有含有缺失值的观测。 na.omit()可以删除所有含有缺失数据的行。

  • 处理日期

我们可以看到在购药时间这一变量下的值中含有"星期五","星期六",这样的字符串,其实这些字符串对我们的分析是没有作用,所以决定把购药时间这一变量下的值进行分裂,并删除含有"星期五","星期六"这诸如此类的字符串。我们决定是使用stringr包中的str_split_fixed()函数进行分割。

> install.packages('stringr')  #stringr安装
> library(stringr)

str_split_fixed()函数定义:str_split_fixed(string, pattern, n)
参数列表:

  1. string: 字符串,字符串向量;

  2. pattern: 匹配的字符。

  3. n: 分割个数

    timesplit<-str_split_fixed(import.csv

    不能识别此Latex公式:
    time, " ",2)
    class(timesplit)   # 用str_split_fixed()函数分割,结果类型是matrix
    [1"matrix"
    import.csv
    time<-timesplit[,1]
    head(import.csv) #检查是否分裂成功
    time cardno drugld drugName saleNumber virtualmoney actualmoney
    1 2016-01-01 1616528 236701 三九感冒灵 7 196 182.00
    2 2016-01-02 1616528 236701 三九感冒灵 3 84 84.00
    3 2016-01-06 10070343428 236701 三九感冒灵 3 84 73.92
    4 2016-01-11 13389528 236701 三九感冒灵 1 28 28.00
    5 2016-01-15 101554328 236701 三九感冒灵 8 224 208.00
    6 2016-01-20 13389528 236701 三九感冒灵 1 28 28.00

由于import.csv

不能识别此Latex公式:
time是为字符型变量,应该转化为日期型变量。可用函数as.Date()执行这种转化。其语法为as.Date(x, "input_format"),其中x是字符型数据, input_format则给出了用于读入日期的适当格式

class(import.csv$time)
[1"character"     #字符串型
import.csv$time<-as.Date(import.csv$time,"%Y-%m-%d")   
> head(import.csv)
        time      cardno drugld   drugName saleNumber virtualmoney actualmoney
1 2016-01-01     1616528 236701 三九感冒灵          7          196      182.00
2 2016-01-02     1616528 236701 三九感冒灵          3           84       84.00
3 2016-01-06 10070343428 236701 三九感冒灵          3           84       73.92
4 2016-01-11    13389528 236701 三九感冒灵          1           28       28.00
5 2016-01-15   101554328 236701 三九感冒灵          8          224      208.00
6 2016-01-20    13389528 236701 三九感冒灵          1           28       28.00
class(import.csv$time)
[1"Date"


  • 数据类型转换


来自猴子数据分析

为了使销售数量、应收金额、实收金额下的数据类型都为数值型,所以都做了以下的转换。


import.csv$saleNumber<-as.numeric(import.csv$saleNumber)
import.csv$virtualmoney<-as.numeric(import.csv$virtualmoney)
import.csv$actualmoney<-as.numeric(import.csv$actualmoney)


  • 数据排序
    在R中,可以使用order()函数对一个数据框进行排序。默认的排序顺序是升序。添加decreasing=TRUE时为降序即可得到降序的排序结果。



      

    import.csv<-import.csv[order(import.csv

time,decreasing = TRUE),]

head(import.csv)

time cardno drugld drugName saleNumber virtualmoney actualmoney

57 2016-07-19 1616528 236701 清热解毒口服液 1 28 28

862 2016-07-19 10013306428 2367011 开博通 1 31 28

863 2016-07-19 10030713328 2367011 开博通 4 124 118

864 2016-07-19 10059383628 2367011 开博通 2 62 56

865 2016-07-19 101409528 2367011 开博通 2 62 56

866 2016-07-19 13406628 2367011 开博通 2 62 56

数据分析

  • 月消费次数

月均消费次数=总消费次数 / 月份数,并且同一天内,同一个人发生的所有消费算作一次消费。对于同一天和同一个人,我们可以认为是时间和社保卡号(暂且认为一个人使用一张社保卡)都是相同的,然后把同一人和同一天的重复项删除,即可得到总消费次数。

> kpi1<-import.csv[!duplicated(import.csv[,c("time","cardno")]),]
> consumernumber<-nrow(kpi1)
> consumernumber
[1] 5398

其中,duplicated 判断对象的每个取值是否重复,如duplicated(c(1,1,2,3)) 返回 FALSE TRUE FALSE FALSE ,其中TRUE对应的为重复的值。

判断月份数:刚刚我们关于时间的排序选择的是降序,所以时间这一序列下第一个值是最大值,最后一个值是最小值。我们用最大值减去最小值就能够得出实际天数,因为每月是30天,所以相除就能得到月数。

> starttime<-kpi1$time[1]
> endtime<-kpi1$time[nrow(kpi1)]
day<-starttime-endtime
month<-day%/%30
Error in Ops.difftime(day30) : '%/%'对"difftime"对象不适用
class(day)     #查看day的类别
[1"difftime"
day<-as.numeric(day)  #转换成数值型
day
[1200
month<-day%/%30   #%/% 表示取整
month
[16

所以:月均消费次数=总消费次数 / 月份数

   > monthconsume<-consumernumber%/%month
   > monthconsume
      [1] 899
  • 月均消费金额

月均消费金额=总消费金额/ 月份数,这里的总消费金额,我们选择的是实收金额的取和得来的。

> totalmoney<-sum(import.csv$actualmoney,na.rm=TRUE)
> monthmoney<-totalmoney/month
> monthmoney
[1] 50771.71

原因如果实收金额中有一个缺失值的话,默认选项na.rm=FALSE会导致R函数sum返回NA,添加na.rm=TRUE就不会出错了。

  • 客单价

客单价=总消费金额 / 总消费次数

    >pct<-totalmoney/consumernumber
    > pct
    [156.43391
  • 消费趋势

首先让实际消费金额按照日期(周)的分类进行求和得到下面的数据。

> week<-tapply(import.csv$actualmoney,format(import.csv$time,"%Y-%U"),sum)
  #format(import.csv$time,"%Y-%U")表示将import.csv$time转化成这种"%Y-%U"格式
  #"Y%"表示四位数的年份,"%U"表示第多少周(一年共有52周,从第0周开始);
#tapply(import.csv$actualmoney,format(import.csv$time,"%Y-%U"),sum)
  表示将实际消费金额按照"%Y-%U"这种日期格式进行分类并求和
> week      #得到了这样的一组数据
 2016-00  2016-01  2016-02  2016-03  2016-04  2016-05  2016-06  2016-07  2016-08  2016-09  2016-10 
 1972.80  9679.64 10979.01  8719.73 15662.30 18758.82  3665.70  8441.51  8453.57  9988.98  8500.78 
 2016-11  2016-12  2016-13  2016-14  2016-15  2016-16  2016-17  2016-18  2016-19  2016-20  2016-21 
 9869.16 10135.23  8426.46 11400.66 14408.21 10385.33 10265.98  9496.06  9728.40 11794.11 11497.20 
 2016-22  2016-23  2016-24  2016-25  2016-26  2016-27  2016-28  2016-29 
 9530.38 10806.71 11877.43 14077.38 10894.90  8386.97 13372.67  3454.18 

将把数据转换成数据框并再添加一行

> week<-as.data.frame.table(week)   #as.data.frame.table(),这个函数我也没有弄清,自己就选择先记住了
> week   #这是部分的数据
      Var1     Freq
1  2016-00  1972.80
2  2016-01  9679.64
3  2016-02 10979.01
4  2016-03  8719.73
5  2016-04 15662.30

>
 names(week)<-c("time","actualmoney")
  #names():这个函数可以返回一个向量,显示的是用做参数的类型里所有可以用"$"访问的变量名
> week$time<-as.character(week$time)
> week$timeNumber<-(1:nrow(week))     #添加一行

开始画消费趋势图

> plot(week$timeNumber,week$actualmoney,xlab = "时间(年份-第几周)",ylab="消费金额",xaxt="n",main="2016年朝阳区医院消费曲线",col="blue",type="b")
      #xaxt="n"就是先不显示x的刻度,通过axis函数自定义 
> axis(1,at=week$timeNumber,labels = week$time,cex.axis=1.5)
      #1是表示你要对x轴作修改,labels就是要打的内容,
  #at就是你要多少个刻度,cex.axis=1.5表示坐标轴文字放大1.5倍

总结下:月均消费次数为899,月均消费金额为50771.71,客单价为56.43391,消费趋势如下图

通过这几天的学习明显的感觉到了制定计划的极大好处,制定计划之后自己再也不会为什么都没有学会、没有学好而感到焦灼了,而按照计划表慢慢来一步一步实现小目标,不断带来小惊喜。这里应该特别感谢猴哥,因为自己原来一直有计划无用之类的错误概念,是猴哥通过作业的方式倒逼自己做了计划。其次我们的通关都是以文章的形式来呈现,在写的过程中不知不觉的梳理清楚好多概念性问题,也是应了教是最好的学习方式这句话。感谢猴哥。

推荐 0
本文由 DataFrog 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册