R语言统计分析<-‘简单&好用‘

工欲善其事,必先利其器。

为什么要写R语言统计分析?
1. 博主是R的铁粉(使用R编码近10年),由于近期不经常使用R,可能会遗忘一些语法,写个简单的总结,算是给自己的一个备忘录;
2. 给计划学习R的朋友一些帮助;
3. 随着年龄渐长(还有发际线),计划转型(砸键盘,不想写代码了),给编码能力一个小小的总结交代。

从官网下载好R、Rstudio安装包,先装R,再装Rstudio,Rstudio是对R语言的界面优化实现,文中的代码示例均为Rstudio界面。
安装好了吗?
Let's Rstudio!

1. Rstudio常用操作
2. Rstudio函数入门
3. 可以抄作业的R脚本

一、Rstudio常用操作

1. Rstudio界面:
左1:R代码编译区域
左2:R代码执行输出区域
右1:已生成的数据集展示区域
右2:图表绘制+帮助文档help区域

2. 界面风格设置
【菜单->Tools->global options->appearance】
博主喜欢用黑色风格merbivore soft,把注释、代码、函数明显区分开。

3. 出现脚本打开中文乱码怎么办?
【菜单->Tools->global options->code->saving】
将默认文本编码改为"UTF-8",关闭Rstudio后再打开即可。

4. Rstudio快捷键:
执行选中脚本:Ctrl+Enter
清屏:Ctrl+L
注释:Ctrl+shift+C

5. 常用函数地图:

二、Rstudio函数入门

1. 【下载&导入包】
install.packages('包名') # 下载包函数,需要什么函数,查询一下相关包名下载,每台电脑同一个包下载一次即可,下图示例是fread()函数的data.table包
library(包名) # 引用包函数,每次打开Rstudio时,需要引用一次,可能会有warning信息,再执行一次library()函数不报错就可以正常使用

# 一些常用的包
library(data.table) # 用于fread()读取大文件函数
library(readxl) # 用于读取Excel文件
library(xlsx) # 用于读取Excel文件
library(dplyr) # 用于dplyr的group_by计算
library(lubridate) # 日期处理函数包
library(reshape2) # 数据框变形函数包melt()、dcast()
library(sqldf) # 用于在R中使用SQL
library(RSQLite) # 用于在R中使用SQL
library(stringr) # 字符串处理函数包
library(httr) # 指定URL、POST()调用数据
library(DBI) # 连接数据库,获取数据集
library(rJava) # 有些函数依赖Java包,下载报错导入报错可能是因为本地没有Java环境,可以在官网http://www.oracle.com/下载Java包,在本地装好了再在R语言下载导入
library(RJDBC) # 导入驱动程序,数据库导入数据需要的包
library(rlang) # 这个包具体不晓得啥意思,引用其他包的过程中提示需要,跟着下载就行了
library(ggplot2) # ggplot可视化制图函数包
library(gridExtra) # 绘图相关的布局函数包
library(scales) # 绘图相关的可视化参调整数函数包
library(RODBC) # 连接数据库
library(RMySQL) # 连接MySQL数据库
library(RPostgreSQL) # 连接PostgreSQL数据库

2.【数据读写】
list.files(choose.dir()) # 获取指定文件夹内所有文件名
setwd() # 设置工作目录,注意路径是反斜杠或者双斜杠
source('111111.R', encoding = 'UTF-8',echo = TRUE) # 假设有10+个脚本,每天都需要执行1遍,不能每个都打开执行吧,可以写个集合组合脚本

# R语言提供了多种导入数据的方式,如:链接数据库、API获取数据、本地文件读取

# 1. 读取本地Excel文件
read_excel('Excel文件名', sheet='sheet_name') # 读取Excel文件中指定sheet_name的内容

# Excel读取数据经常出现日期异常情况,数据导入后的关键在于还原日期,可以使用origin参数还原
data_order$日期_更新<-as.Date(data$日期,origin='1900-1-1')-ddays(2) # origin的日期参数可以调整,ddays()数值也可以调整,可以找几个日期检验还原的准确性

# 2. API获取数据,以神策分析API导出数据为例
# reshape_date()是自定义函数,用来将API导出的数据进行结构转换,如果是链接神策URL处理数据,可以直接抄作业
reshape_data<-function(data){
  data<-strsplit(content(data, "text"), "\n")
  data<-do.call(cbind,data)
  data<-strsplit(data,split = '\t')
  data<-do.call(rbind,data)
  data<-as.data.frame(data,stringsAsFactors = FALSE)#将data转为数据框
  names(data)<-data[1,]
  data<-data[-1,]
  return(data)
}
url <- 'https://神策地址/api/sql/query?token=神策管理员权限token&project=production' # 神策API数据地址格式,其他平台写入API地址即可
POST(url, body = list(q = paste0("select * from events limit 10"), format='csv')) # paste0()函数中写入SQL语句,可以灵活配置参数,如下图中的date_start

# 3. 链接数据库
conn_db<-odbcConnect('数据库地址',uid= 用户名’,pwd='密码') # 配置需要链接的数据库地址、用户名、密码
sqlQuery(conn_db, paste0("select * from table limit 10")) # paste0()函数中写入SQL语句
dbGetQuery(conn_db,paste0("select * from table limit 10")) # paste0()函数中写入SQL语句

# 4. 读取本地CSV文件
# 来看一个博主超超超超超超级中意的函数:fread()
# 记得第一份工作在银联,每天接触大量的交易流水,动辄几千万行数据,Excel实在是处理不来,只能学习写代码处理数据
# 读取1G数据集需要多少时间?
start_time<-Sys.time() # 标记开始时间,sys.time() 获取当前系统时间的函数
data<-fread('s_cust_product.csv',header = TRUE) # 读取1G的文件毫无压力
end_time<-Sys.time() # 标记读取完成时间
print(paste0('读取数据耗时:',difftime(end_time,start_time,units = 'secs'))) # 输出时间差,paste()函数对输出内容做拼接,difftime计算时间差(单位参数可以在help中查询)
dim(data) # 查看data数据的行数、列数
# 哇!600万+行数据短短6秒时间内完成了读取!惊艳!
names(data) # 查看data数据集的列名,可以在右一区域查看数据框的字段类型
head(data,2) # 查看data前两行数据示例

# 5. 写出数据文件
# 几种常用的输出文件类型:csv、excel、txt,博主使用csv文件较多(可以用notepad++直接打开,也可以Excel打开)
write.csv(数据集,'输出文件名.csv',row.names = FALSE) # row.names=FALSE 为不输出索引列,试一下写vs不写这个参数,看看结果就可以理解啦

3.【数据预处理】
as.character() # 字段类型转换为‘字符串’
as.numeric() # 字段类型转换为‘数值’
rbind() # 数据框加长拼接,要求列名、列数一致,对比SQL语法中的union all
cbind() # 数据框加宽拼接,要求行数一致
unique() # 对数据去重
paste() # 字段拼接处理
subset(data,筛选条件, select = c()) # 对data数据集做筛选
data[data$c1=='1']<-1 # 有筛选地进行数据标识
for () {} # for循环,几乎所有编程语言都会用到
if () {} else {} # 判断函数,经常与for搭配使用
merge(a,b,by = ' ') # 根据指定字段拼接表a与表b,与SQL语法中join相似,有left、rigth、all多种用法
&、|、==、%in%c() # 逻辑判断语法:与、或、等于、是否属于某几个
substr() # 字符串截取
iconv() # 乱码的编码调整
gsub('目标字符','替换字符',列名) # 字符串内指定字符的替换

# 示例开始>>>
data_order<-read_excel('data_order.xlsx',sheet='订单')
head(data_order,2)
data_order$purchasedate<-as.character(data_order$purchasedate) # 查看各个字段的类型,将format转换为character字符类型

# 1. 创建几个数据集,看看筛选、拼接函数的用法---subset()、rbind()、cbind()
# a1:筛选data_order中,purchasedate等于2012-12-01 且 profit大于等于10的行,以及这几列:'orderid','purchasedate','type','subtype','profit'
# a2:筛选data_order中,purchasedate等于2012-12-01 或 profit大于等于10的行,以及这几列:'orderid','purchasedate','type','subtype','profit'
# a3:筛选data_order中,purchasedate等于2012-12-01 且 profit大于等于10的行,以及这几列:'shipdate','shipway'
a1<-subset(data_order,purchasedate=='2012-12-01' & profit>=10, select = c('orderid','purchasedate','type','subtype','profit'))
a2<-subset(data_order,purchasedate=='2012-12-01' | profit>=10, select = c('orderid','purchasedate','type','subtype','profit'))
a3<-subset(data_order,purchasedate=='2012-12-01' & profit>=10, select = c('shipdate','shipway'))
dim(a1)
dim(a2)
dim(a3)
# a1 vs a2:同列不同行,用rbind函数实现加长拼接
# a1 vs a3:同行不同列,用cbind函数实现加宽拼接
a12<-rbind(a1,a2)
dim(a12)
a13<-cbind(a1,a3)
dim(a13)

# 2. 去重、筛选标记函数用法
unique(data_order$subtype) # 去重函数,看看销售了哪些种类的商品,即对data_order中subtype去重展示
data_order$label_type1<-paste(data_order$type,'-',data_order$subtype) # 字段拼接,将date_order的type(大类)与subtype(子类)用-拼接,生成新字段label_type1
head(data_order,2)
data_order$label_type2[data_order$subtype %in% c('复印机','纸张')]<-'打印用品' # 有筛选地进行数据标记,筛选出subtype中包含'复印机'、'纸张'的订单,用新字段label_type2标记为'打印用品'
tail(data_order,5) # 查看后5行数据

# 3. 上一步也可以使用for()+if()函数,实现打标签,用label_type3来标识吧
n<-dim(data_order)[1] # 用n记录date_order的行数
# 遍历data_order的每一行,并且对每一行进行判断
for (i in 1:n) {
  if (data_order$subtype[i] %in% c('复印机','纸张'))
    {     data_order$label_type3[i]<-'打印用品'     }
  else
    {  data_order$label_type3[i]<-''     }

  if ((i/n*100)%%2==0) {
    print(paste0(round(i/n,2)*100,'%'))    } # for循环执行进度
}
tail(data_order,5) # 查看data_order数据集后5行

# 4. 拼接函数merge()---划重点,这个函数很重要!
# 先看两个数据集,a1是订单明细表,a2是商品信息表,我们需要给a1订单表匹配出productid的类别信息
head(a1,2)
head(a2,2)
aa<-merge(a1,a2,by = c('productid'),all.x = TRUE) # 根据productid进行左拼接
head(aa)

# 5. 字符串处理
aa$productid_sub1<-substr(aa$productid,1,3) # 字符串截取,截取productid前3个字符
aa$productid_sub2<-gsub('-ADV','',aa$productid) # 字符串内指定字符的替换,将productid中'-ADV'替换为空
head(aa)

4.【数据计算&统计】
Sys.Date()-ddays(i) # 获取当前日期i天前的日期
difftime(end_time,start_time,units = 'days') # 计算日期差,其中units参数包括:"secs", "mins", "hours","days", "weeks"
round(a,2) # 四舍五入,保留2位小数点
is.na() # 判断是否为缺失值
sample() # 生成指定概率的随机数
data%>%group_by(c1)%>%dplyr::summarise(n1=n_distinct(c2)) # 分组去重计算
data%>%groupby(date)%>%mutate(rn=rank(time)) # 分组排序,SQL里的row_number()
sqldf("SQL语句",drv = "SQlLite) # 在R中使用SQL
stringr::str_detect(table$cust id,'123') # 字符串判断,是否包含123
weekdays() # 计算日期的星期
nchars() # 计算字符串长度
var() # 计算方差
sd() # 计算标准差
mean() # 计算均值
sqrt() # 计算开根号
abs() # 计算绝对值
cor() # 计算相关系数
table() # 计算频数分布
summary() # 计算关键统计数据,均值、最大值、最小值、中位数、上下4分位数
quantile(data$cl,probs = seq(0, 1, 0.1), na.rm = TRUE) # 计算分位数,十分位,可灵活设置分位点
data[order(data$c1,decreasing = FALSE),] # 数据框根据某一列排序,经常用在输出结果的日期排序上
melt() # 行列转换,宽表变长表,列转行
dcast() # 行列转换,长表变宽表,行转列

# 1. 聚合计算:dplyr包中group_by()
data_order<-read_excel('data_order.xlsx',sheet='订单')
head(data_order,2)
# 计算每天的订单量、下单客户数、交易额、利润率
data_res<-data_order%>%group_by(purchasedate)%>%dplyr::summarise(订单量=n_distinct(orderid),
                                                                 下单客户数=n_distinct(custid),
                                                                 交易额=sum(sales*quantity),
                                                                 利润率=sum(profit))
head(data_res)
data_order$date_gap<-difftime(data_order$shipdate,data_order$purchasedate,units = 'days') # 计算发货时效,发货时间与购买时间的日期差
head(data_order,2)

# 2. 计算数据分布的函数
table(data_order$date_gap) # 计算发货时间差的频数分布
summary(data_order$profit) # 计算关键统计数据,订单利润的均值、最大值、最小值、中位数、上下4分位数
quantile(data_order$date_gap,probs = seq(0, 1, 0.1), na.rm = TRUE) # 计算发货时间差的十分位数
quantile(data_order$profit,probs = seq(0, 1, 0.1), na.rm = TRUE) # 计算订单利润的十分位数
round(quantile(data_order$profit,probs = seq(0, 1, 0.1), na.rm = TRUE),2) # 计算订单利润的分位数,并且保留两位小数点

# 3. 在R中使用SQL语法
# 计算各个国家的交易额,且给出排名
data_cate<-sqldf("select country,sum(sales*quantity) as amt
                 from data_order
                 group by country",drv = 'SQLite')
head(data_cate)
data_cate<-data_cate[order(data_cate$amt,decreasing = TRUE),] # 对汇总后的结果,根据amt做降序
data_cate<-data_cate%>%group_by()%>%mutate(rn=rank(amt)) # 分组排序,SQL里的row_number(),默认升序排列
data_cate<-data_cate%>%group_by()%>%mutate(rn_sub=rank(-amt)) # 分组排序,SQL里的row_number(),金额写为负值,即可实现金额的降序
head(data_cate)

# 4. 生成随机分组
group<-as.data.frame(sample(c('A','B','C'), # 生成哪些组?
                            1000, # 生成多少行数据?
                            replace = TRUE,
                            prob = c(0.33,0.33,0.33))) # 每个组出现的概率
names(group)<-c('group_name') # 对数据框group定义列名
table(group$group_name) # 查看各个组的频数

# 5. 统计学&其他函数
data_order$weekday<-weekdays(data_order$purchasedate) # 计算日期的星期
data_order$type_nchars<-apply(data_order[,9],1,nchar) # 计算字符串长度
var(data_order$profit) # 计算订单利润的方差

5.【绘图】
# 主要使用ggplot函数
# 具体参数代表啥意思可以参考下方图片

theme_set(theme_bw())

plot_profit<-ggplot(data=sales_sum,aes(x=year,y=profits,group=1))+
  geom_line(size=0.6,colour='firebrick')+
  labs(x="半年度",y="利润额",title="整体 利润额 变化趋势")+
  theme(plot.title = element_text(hjust = 0.5,face = "bold"),
             axis.text.x = element_text(angle = 50,vjust=0.5))

plot_profit_rate<-ggplot(data=sales_sum,aes(x=year,y=profits_rate,group=1))+
  geom_line(size=0.6,colour='blue')+
  labs(x="半年度",y="利润率",title="整体 利润率 变化趋势")+
  theme(plot.title = element_text(hjust = 0.5,face = "bold"),
        axis.text.x = element_text(angle = 50,vjust=0.5))+
  scale_y_continuous(labels=percent)

grid.arrange(plot_profit,plot_profit_rate,ncol=2)

# ggplot博主不是特别精通,感兴趣的朋友可以点击这个链接学习
# 如何用ggplot2绘制漂亮的统计图形   https://mp.weixin.qq.com/s/RKNAt0upMJTu2MvNuavgCw
# 如何使用ggplot2绘制多图组合   https://mp.weixin.qq.com/s/IHDi255ZKRSVEk7c8ZcDwA

三、可以抄作业的R脚本

1. 读取目录下所有带关键词的文件名,将这些文件的数据合并
load_df <- function(path,file_pattern,colclasses=NULL) {
  files = dir(path=path)
  files_d <- NULL
  for(i in 1:length(files)){
    file <- files[i]
    file_full<-paste0(path,file)
    print(file_full)
    if(stringr::str_detect(file, file_pattern)){
      print('ok')
      files_d=rbind(files_d,fread(file_full,header = TRUE,encoding = 'UTF-8', colClasses=colclasses))
    }
  }
  return(files_d)
}
data_order<-load_df('文件路径\\','文件名关键词')

2. 将读取的文件/数据进行拼接,以读取神策近31天数据为例
n<-31
for (i in 1:n) {
  date_sensor_start<-Sys.Date()-ddays(i)
  visitor_sensor_01<-POST(url,body = list(q = paste0("select * from events where date='",date_sensor_start,"'"),format='csv'))
  visitor_sensor_01<-reshape_data(visitor_sensor_01)
  if (i==1) {
    visitor_sensor<-visitor_sensor_01
  }else{
    visitor_sensor<-rbind(visitor_sensor,visitor_sensor_01)
  }
}

3. 分组计算十分位数
cust_test<-cust_test%>%group_by(group)%>%dplyr::summarise(cust_cnt=n_distinct(cust_id),
a0=quantile(n,probs = c(0)),
a1=quantile(n,probs = c(0.1)),
a2=quantile(n,probs = c(0.2)),
a3=quantile(n,probs = c(0.3)),
a4=quantile(n,probs = c(0.4)),
a5=quantile(n,probs = c(0.5)),
a6=quantile(n,probs = c(0.6)),
a7=quantile(n,probs = c(0.7)),
a8=quantile(n,probs = c(0.8)),
a9=quantile(n,probs = c(0.9)),
a10=quantile(n,probs = c(1)))

写到这里想到了‘文心一言’,想看看机器学习会如何来回答这个问题,下图是文心一言给出的回答之一;
不得不说,文心一言的回答比博主手动码字的深度和广度更高,可能详细程度稍弱一些。

文末:
人生坎坎,山山而峦,不过尔尔;
心路漫漫,水水而川,如此悠悠。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值