这是一个java小码农的跨界试探,如果你对R感兴趣可以买本R语言入门与实践,因为这里只记录了本人觉得有用的基本知识点.如果你只是看个乐呵,祝你有所收获.

数据分析具备三个属性

  • 可再现性
  • 自动化
  • 沟通

R的传统强项是建模与作图

1. R基础

1.1 R用户界面

冒号运算符:表示返回两个整数值之间的所有整数.
1:100

R是一种动态编程语言,意味着运行R代码时,变异操作会由R自动完成.

#是注释符号

1.2 对象

赋值<-

对象名不能以数字开头,特殊符号不能出现在名称中^ ! $ @ + - / *

R区分大小写

同一个对象再次被赋值时,R会自动覆盖存储对象中的信息,不会请求批准

ls命令查看已经命名了哪些R对象ls()

对于两个不等长的向量,R会重复较短的向量以执行元素方式运算.

如果长向量的长度值不是短向量长度值的整数倍,R返回运算结果的同时也会返回一条警告消息.这种行为称为向量循环

如果需要使用矩阵乘法时,可使用%*%行内乘法,%o%行外乘法

1.3 函数

  • round 函数四舍五入

  • factorial 阶乘操作

  • mean 平均值

  • sample(x=1:4,size=2) 从向量x中抽取size个元素并返回(默认使用不可放回抽样,可以设置参数replace=TRUE设为可放回抽样)

  • args(round) 查看round函数的所有参数名

  • typeof 查看某对象是什么类型

  • attributes 查看对象属性

给多个参数的函数设置参数值时候,将数据对象的名称与参数名用等号连起来,避免错误传递数据.R用户大多不会指定R函数的第一个参数的名称.

1.5 编写自定义函数

R函数包含三个部分:函数名,函数主体,参数集合

my_function<-function(x=默认值){}

如果键入函数名而不带上括号,那么R只会展示这个函数所存储的代码.如果带上这对括号,R就会运行这个函数所存储的代码.

R顺序执行函数主体的所有代码,并返回最后一行代码的运行结果,如果最后一行没有返回值,整个函数也不会返回值.

可以指定初始默认值

roll2<-function(bones=1:6){dice<-sample(bones,size=2,replace=TRUE)sum(dice)
}

提取函数

Code>Extract Function

1.8 小结

R语言两个重要组成部分:

  • 对象用来存储数据
  • 函数用来操作数据

2. R包与文档

R包

qplot来自R中的ggplot2包(可视化包),需先下载安装ggplot2包

R包可以从R官网下载: https://cran.r-project.org

也可以命令窗口运行命令:install.packages("ggplot2")

安装只是将R包安装在计算机的硬盘上.还需要在R会话中利用命令library("ggplot2")加载该包.

c()收集数据,例如x<-c(-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4)

library("ggplot2")
x<-c(-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4)qplot(x)
# 直方图
qplot(x,binwidth=1)

replicate重复运行指定次数

replicate(3,1+1)
## 2 2 2

?sample查看帮助页面?+函数名

3. R对象

R中最简单的对象类型叫做原子型向量

原子型向量就是最简单的包含数据的向量die<-c(1,2,3,4,5,6)

is.vector测试某对象是否为原子型向量

双整型 numeric

双整型向量用来存储普通的数值型数据.数值可正可负,可大可小,R中键入的任何一个数值都默认以双整型存储.

typeof函数查看某个对象到底是什么类型.

整型 integer

整型数据的数值不需要小数点成分.

int<-c(-1L,2L,4L)
typeof(int)
## "integer"

4与4L唯一的区别就在于他们的存储方式.在计算机内存中,整型的定义方式比双整型更精确(除非整数非常大或非常小)

每个双整型的数值都只会大约精确到小数点后16位.

sqrt(2)^2-2肯定不等于零,因为有浮点误差.

字符型 character

逻辑性 logical

逻辑型向量存储TRUE,FALSE

全部大写不加引号 TRUE,FALSE

复数类型和原始类型 complex,raw

复数类型向量存储复数(complex)

原始类型向量用来存储数据的原始字节(raw(n))

3.2 属性

属性不会影响对象取值,显示该对象时也不会出现属性信息.属性算是对象的元数据(metadata)

attributes函数查看对象包含哪些属性信息,如果没有任何属性信息,会返回NULL

原子向量最常见的三个属性:名称,维度,类

每种属性都有自己的辅助函数,将相应属性附加给某个R对象,也可以查看属性值.

名称属性

# names赋值(字符向量长度应与die等长)
names(die)<-c("one","two","three","four","five","six")# names查看对象名称属性
names(die)
## "one","two","three","four","five","six"# 一次性删除名称属性值
names(die)<-NULL

维度属性

dim函数

# 2*3矩阵(两行三列)
dim(die)<-c(2,3)
# 3*2矩阵(三行两列)
dim(die)<-c(3,2)# 1*2*3叉立方体(一行两列三切片)
dim(die)<c(1,2,3)

第一个值赋给行数,第二个数赋给列数.

第一列排满,再跳第二列排列

可人为控制(matrix或array函数)

3.3 矩阵

#matrix函数默认先排满第一列,再排第二列(设置byrow=TRUE)可先排第一行再排第二行
m<-matrix(die,nrow=2,byrow=TRUE)
m<-matrix(die,ncal=5,byrow=TRUE)# array函数生成n维数组
ar<-array(C(11:14,21:24,31:34),dim=c(2,2,3))

3.5 类

类是原子型向量的一个特例.比如矩阵die是特殊双整型向量

改变die维度属性,R会添加一个class属性.这属性描述die具有的新格式.

class函数搜索class属性

class("Hello")
##"character"

3.5.1 日期,时间

除了六种类型:双整型,整型,字符型,逻辑性,复数型,原始型

R的属性系统还能表示更多数据类型

# 返回当前时间
now<-Sys.time()
now
## 2021-09-10 15:38 UTCtypeof(now)
## "double"class(now)
## "POSIXct" "POSIXt"# 移除class属性
unclass(now)
## 1395057600

POSIXct框架下,时间表示为1970年1月1日零点(UTC时区)开始逝去的秒数,POSIXct框架下被存储为数值

R中有很多类,但是有一个特殊类:因子 factor

将因子视为与性别类似的概念,可取特定值(男性女性),特定值之间有特殊的顺序规定(女士优先)

gender<-factor(c("male","female","female","male"))
typeof(gender)
## "integer"

因子看起来像字符串,其实表现为整数值.

as.character函数将一个因子强制转换成字符串.R会将因子的标签信息保存为一个字符串向量,摒弃内存中的整数值信息.

3.6 强制转换

如果一个原子型向量包含字符串,R会将该向量中所有元素都转换成字符串

如果一个原子型向量只包含逻辑型和数值型元素,R会将逻辑型全部转换成数值型

对逻辑型向量进行运算,R会应用相同的转换规则

sum(c(TRUE,TRUE,FALSE,FALSE))
## 2

也可以明确告诉R将数据从一种类型强制转换为另外的类型

as.character(1)
as.logical(1)
as.numeric(FALSE)

向量,矩阵,数组 只能存储一种类型的数据,R知道这些数据对象中只有一种数据类型,因此对数据的操作更直接和高效.向量,矩阵,数组的数据在内存中的存储方式比较简单,对它们的数据操作更快.

3.7 列表

列表将数据组织在一个一维集合,类似原子向量,但是组织的是R对象.

list1<-list(100:130,"R",list(TRUE,FALSE))

列表是R中全能型的存储工具,可存储任何类型的数据

3.8 数据框

列表的二维版本,可类比Excel表格的存储形式

每一列都可以用来存储一种类型的数据,列与列之间的数据类型可以不同,每一列中的所有元素必须是同一种类型的数据.

手动创建数据框data.frame函数

每个向量都有自己的名称来描述向量信息

df<-data.frame(face=c("ace","two","six"),suit=c("clubs","clubs","clubs"),value=c(1,2,3))
dfface  suit value
1  ace clubs     1
2  two clubs     2
3  six clubs     3

确保每个向量长度相等,数据框不能组合不等长的向量.

每个数据框都是一个具有data.frame类的列表,str函数查看这个列表(数据框)中,哪些对象被组织在一起.

typeof(df)
## "list"
class(df)
## "data.frame"# stringsAsFactors=FALSE 防止R将字符串转成因子,R很喜欢这么做
df<-data.frame(face=c("ace","two","six"),suit=c("clubs","clubs","clubs"),value=c(1,2,3),stringsAsFactors=FALSE)> str(df)
'data.frame': 3 obs. of  3 variables:$ face : chr  "ace" "two" "six"$ suit : chr  "clubs" "clubs" "clubs"$ value: num  1 2 3

.csv后缀的文件是逗号分隔值(Comma-Separated Values)文件,简称CSV文件

R可以导入.csv文件

head和tail用于快速查看大型数据集

head默认前六行,tail默认后六行,具体行数均可指定.

# R将数据框转换成逗号分隔纯文本文件,并将该文件保存在当前工作目录下
# deck是数据框名称,file文件名带后缀, row.names=FALSE避免在数据开头添加行号数字
write.csv(deck,file="cards.csv",row.names=FALSE)# 查看当前工作目录的路径
getwd()# 更改路径RStudio>Session>SetWorkingDirectory>ChooseDirectory进行更改
单一数据类型 多种数据类型
一维 向量 列表
二维 矩阵 数据框
n维 数组

R中常用的数据结构为向量,矩阵,数组,列表,和数据框

R可以打开许多不同格式的文件,如果确定需要在R中完成所有工作,可以用R自己的文件格式,会节省内存和时间.

4. R的记号体系

可通过R的记号体系实现R对象中值的选取.

4.1 值的选取

六种方式创建索引

  • 正整数(索引始于1)
# deck是一个数据框# 重复取第一行两次
deck[c(1,1),c(1,2,3)]# 如果只取一列,R会返回一个向量
deck[1:2, 1]
# 如果仍想返回一个数据框,可在中括号内添加参数drop=FALSE
deck[1:2, 1, drop=FALSE]
  • 负整数
# 除了第一行的其他行 1-3列
deck[-1,1:3]
# 不提取任何信息,返回空对象
deck[0,0]
  • 空格
# 提取索引位置所代表维度的所有元素
  • 逻辑值
vec<-c(6,1,3,6,10,5)
vec[c(F,T,F,T,F,T)]
## 1,6,5

索引向量必须与待提取元素向量长度相同

  • 名称
# 数据框中提取列的常用方法,因为列总有名称
deck[1,c("face","suit","value")]

两种对象可以使用第二种记号体系.

$提取数据框或者列表对象中的值

列名不需要加双引号

deck$value

提取一个列表对象中的元素,如果元素有名称的话,同样可以利用$来完成

对列表对象的任何操作都只能返回列表对象.不过当使用$时,R会原封不动地提取元素,因此得到的元素不再是一个列表对象.

如果列表中的元素没有名称或者不想使用名称,可以使用双中括号代替单中括号提取子集.这样的记号方式与$的效果等同.

list[[1]]

明确性是良好的编程习惯.

5. 对象改值

副本的数据上进行修改,可确保任何时候有原始数据做参考.

vec<-c(0,0,0,0,0,0)
vec[c(1,3,5)]<-c(1,1,1)
vec
## 1 0 1 0 1 0# 添加新变量
vec[7]<-0
vec
## 1 0 1 0 1 0 0# 添加新变量
deck2$new<-1:52
# 移除新变量
deck2$new<-NULL

逻辑值取子集

vec[c(FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE)]

R的七种逻辑运算符

> > =< <= == !=%in%  a %in% c(a,b,c) a是否在c(a,b,c)中

注意:

a=b与a<-b的效果完全一样,是赋值操作.

# A牌点数修改
deck$value[deck$face=="ace"]<-14

逻辑值取子集是R的强项之一,对于向量化编程至关重要,可以让你写出可快速高效运行的R代码.

他娘的学学又出来一个向量化编程,让不让娃活了.老子就是为了看懂一本ODPS的书才来学的R基础,又搞出个向量化编程.网上解释也TN的不说人话,完全看不懂.

布尔运算符将多个逻辑测试整合成一个测试语句

R的6种布尔运算符

运算符 语法 判别
&
|
xor xor(cond1,cond2) 是否只有一个为真?
!
any any(cond1,cond2,cond3,…) 所有条件中是否至少有一个为真?
all all(cond1,cond2,cond3…) 所有条件是否同时为真?
queenOfSpades<-deck4$face=="queen" & deck$suit=="spades"

5.3 缺失信息

R中的特殊字符NA代表"不可用",用来存储缺失信息

大多数R函数都有一个可选参数 na.rm 代表将NA移除(NA remove).如果添加了参数na.rm=TRUE,那么R会在对函数求值时忽略NA.

# 判断是否为NA
is.na(NA)
## TRUE

6. 环境

每一个对象都存储在一个环境(environment)当中.概念上接近于计算机上的文件夹.每一个环境都有一个父环境.

pryr包中的parenvs函数查看R的环境系统

parenvs(all=TRUE)会返回当前会话包含的环境列表.

> library(pryr)
> parenvs(all=TRUE)label                             name
1  <environment: R_GlobalEnv>        ""
2  <environment: package:pryr>       "package:pryr"
3  <environment: package:devtools>   "package:devtools"
4  <environment: package:usethis>    "package:usethis"
5  <environment: 0x00000130fbee7800> "tools:rstudio"
6  <environment: package:stats>      "package:stats"
7  <environment: package:graphics>   "package:graphics"
8  <environment: package:grDevices>  "package:grDevices"
9  <environment: package:utils>      "package:utils"
10 <environment: package:datasets>   "package:datasets"
11 <environment: package:methods>    "package:methods"
12 <environment: 0x00000130fa1f0bc8> "Autoloads"
13 <environment: base>               ""
14 <environment: R_EmptyEnv>         ""

层次最低的环境叫 R_GlobalEnv,它的父环境为 package:pryr,以此类推,最高环境是R_EmptyEnv,是唯一没有父环境的环境.

R的环境系统其实并不存储在文件系统中,而是存储在RAM内存中.

R环境的树形结构不支持自上而下的搜索.

操作R环境

# as.environment函数接受一个环境名称(字符串)作为输入,并返回该名称所对应的环境.
as.environment("package:stats")
## attr(,"name")
## [1] "package:stats"
## attr(,"path")
## [1] "C:/Program Files/R/R-4.1.1/library/stats"

环境树有三个环境拥有自己的调用函数

  • 全局环境 globalenv()
  • 基环境 baseenv()
  • 空环境 emptyenv()

ls()命令或者ls.str命令查看存储在环境中的对象.ls命令只返回对象名称;

ls.str()命令则会大致展示每个对象的结构.

打开R会话后创建的所有对象都会存储在全局环境中.

# 从全局环境中提取deck这个对象
globalenv()$deck# assign将对象存储到某个特定环境中; "new" 是新对象名称; "Hello Global"是新对象取值;如果该环境已经存在 "new"对象,也会直接覆盖对象值
assign("new","Hello Global",envir=globalenv())

6.2 操作R环境

任何时候,R的活动环境只有一个.所有新对象都会被存储在该环境中.通常来说,活动环境就是全局环境,但是当你运行函数时,活动环境可能会改变.

environment()函数查看当前的活动环境.

6.3 作用域规则

  • R首先在当前的活动环境中搜索对象.

  • 命令行中工作时,活动环境就是全局环境.因此,命令行中的所有调用都会发生在全局环境

  • 没有搜索到对象时,R会进入父环境搜索,以此类推直到找到该对象,或达到空环境停止.

函数也是一种R对象

6.4 赋值

给对象赋值时,如果活动环境已经存在具有相同名称的对象,R会覆盖掉原值.

R每次运行函数都会创建一个新的活动环境,函数的运行是在新环境中进行的.

6.5 函数求值

运行环境是R在运行函数求值时创建的环境

函数的运行时环境与第一次创建该函数时所在的环境相连.该函数的所有运行时环境都会将其作为父环境,叫做原环境

# environment函数查看show_env函数的原环境
environment(show_env)

运行时环境的父环境并不一定是全局环境;函数第一次创建时所在的环境才是该函数运行时环境的父环境.

6.6 闭包

让自己定义的函数的原环境不是全局环境,返回值比如可以用列表存储需要返回的函数对象等并返回,方便使用.这样可以保证安全性.这非常非常重要

7.程序

7.3 else

trunc函数接收一个返回整数部分.

a-trunc(a)是返回数值a的小数部分的方法.

  • unique() 不重复的值个数 1,2,1,2 算 2
  • trunc()
  • length()
  • unname() 返回对象副本,并移除其名称属性

&& 和 || 不是向量化的运算符,两侧只能进行单个逻辑测试.

eg:

all(symbols %in$ c(“B”,“BB”,“BBB”))

7.4 查找表

# payouts是一种查找表,其实就是一个R对象,可通过它查找某个集合内的取值.
payouts<c("DD"==100,"7"=80,"BBB"=40,"BB"=25,"B"=10,"C"=10,"0"=0)# 名称取子集
payouts["DD"]
## DD
## 100# 不保留名称,只取中奖金额
unname(payouts["DD"])
## 100

if树有弊端,沿着if树运行,可能要执行很多不必要的计算工作.

如果每个分支只是一些不同的赋值操作,代码基本相似,建议使用查找表.

  1. 明确要赋的值,并将这些值存储在一个向量中
  2. 提取各if树中条件语句
    1. 如果条件中使用了字符串,就用基于名字取子集的方法找到对应元素.
    2. 如果条件中使用整数数值,就用基于整数的取子集方法.

7.6 小结

尝试将任务分解为一些简单的任务,有必要可以再分解为更简单的任务.所有子任务无误时,整合成一个函数.

对自己的代码负有绝对的绝对的检查和修复的责任

8. S3

S3是R自带的类系统.一些函数会首先查询对象的S3类,再根据其类属性做出相应的响应.

print函数就是这样,数值型会显示一个数字,但如果赋予数字后面跟着POSIXt的S3类POSIXct,print将显示一个时间.

R的S3系统有三个组成部分

  1. 属性(class属性等)
  2. 泛型函数
  3. 方法

8.2 属性

# attributes函数查看DECK对象的属性
attributes(DECK)#属性的辅助函数
names()
dim()
class()row.names()
levels()

R允许为某个对象添加任何必要的属性(大多数属性都会被R忽略).只有某个函数需要找到某个属性而又找不到时才会抱怨.

one_play<-play()
one_play# 赋予one_play一个名为symbols的属性
attr(one_play,"symbols")<-c("B","0","B")
attributes(one_play)# 取某个属性的取值
attr(one_play,"symbols")# 如果将某个属性赋给原子向量,R通常将该属性显示在向量值的下方.如果该属性改变了这个向量的类,R可能会用新的方式显示这个向量包含的所有信息.

利用structure函数,第一个参数是R对象或对象取值,剩下的参数是想要添加这个对象的属性.

symbols<-get_symbols()
structure(score(symbols),symbols=symbols)# 将所有符号压缩为一个字符串.
symbols<-paste(symbols,collapse=" ")# 正则表达式另起一行拼接'$'符号.
string<-paste(symbols,prize,sep="\n$")
# 控制台显示正则结果,去掉其中的引号. 与print相似,但是不显示双引号,且会将 \n当做换行
cat(string)

8.3 泛型函数

print就是一个泛型函数,print不是普通函数,print在不同场合完成不同的任务.

比如打印数字类型时,如果是时间类的,则会显示时间,如果不是,则会显示数字

8.4 方法

当你调用print函数时,它其实调用了一个特别的函数,UseMethod

UseMethod检查你提供给print函数的第一个参数的类属性,然后将你提供的待输出对象交给新函数处理,这个函数专门处理具有某种类属性的输入对象.比如你向print提供一个类属性POSIXct的对象时,UseMethod会将print函数的所有参数交给print.POSIXct函数处理.如果类属性为因子,则UseMethod会交给print.factor函数处理.

print.POSIXct和print.factor被称为print函数的方法.这两个函数本身是普通的R函数,特别之处在于UseMethod会调用它们去处理具有对应类属性的对象.

print函数就支持将近200中方法

泛型函数,方法,和基于类的分派方式构成的系统是R的S3系统.源于S语言的第三个版本,是R语言的前身,常用的R函数许多都是S3泛型函数,

S3系统使R函数在不同场合有不同表现.

方法分派

S3方法前一部分指明方法对应的函数,后一部分指明类属性,中间用.分隔.比如print.function和summary.matrix等

UseMethod需要调用某个方法时,会搜索是否存在一个R函数的名称符合以上描述的S3风格,它只需要一个正确的名字.

# 类属性名称slot
class(one_play)<-"slots"args(print)
## function(x,......)
## NULL# 这个方法要和print的入参一致
print.slots<-function(x,......){cat("I'm using the print.slots method")
}print(one_play)
## I'm using the print.slots method# 移除slots属性
rm(print.slots)

如果R对象有多个类属性,UseMethod会首先寻找并匹配对象类属性向量中的第一个属性.如果找不到一个对应的类方法,UseMethod就会尝试匹配第二个类属性,以此类推.

print函数运行时,如果对象的类没有匹配的print方法,nameUseMethod将调用一个名为print.default的特殊方法,该方法专门处理一般情况.

get_symbols<-function(){wheel<-c("DD","7","BBB","BB","B","C","0")sample(wheel,size=3,replace=TRUE,prob=c(0.03,0.03,0.06,0.1,0.25,0.01,0.52))
}score<-function(symbols){# 计算中奖金额same<-length(unique(symbols))bars<-symbols %in% c("B","BB","BBB")if(same){payouts<-c("DD"=100,"7"=80,"BBB"=40,"BB"=25,"B"=10,"C"=10,"0"=0)prize<-unname(payouts[symbols[1]])} else if(all(bars)){prize<-5}else{cherries<-sum(symbOls=="C")prize<-c(0,2,5)[cherries+1]}diamonds<-sum(symbols=="DD")prize*2^diamonds}play<-function(){symbols<-get_symbols()structure(score(symbols),symbols=symbols,class="slots")}
one_play<-play()
one_play
print(one_play)#=======输出结果=======
## BB BB 0
## $25

8.5 类

创建一个类

  1. 类起名.
  2. 给属于该类的每个对象赋class属性.
  3. 为属于该类的对象编写常用泛型函数的类方法.

methods函数指定想要查找的class属性作为参数(字符串).methods函数会返回R中已存在的针对该类的所有方法.如果某个R包没有加载过,其中的方法不会出现在method的返回结果中.

创建一个类,需要做很多工作,为R中每一个基本操作编写对应的类方法函数

R在将多个对象组成一个向量时会丢弃对象的属性(如类属性)

R在对某个对象取子集时也会丢弃其属性

8.6 S3与调试

如果一个函数调用了UseMethod,就很难知道这个函数真正是做什么的.

8.7 S4和R5

比S3使用难度更大,更少见.提供S3没有的防护措施.相关书籍<<Advanced R Programming>>

8.8 小结

S3系统是R的面向对象编程

9. 循环

9.1 期望值

事件每个可能结果乘以权值(出现的概率)所得结果的总和.

各可能结果概率相同,期望值就是平均值.

9.2 expand.grid

快捷写出n个向量元素的所有组合.

die<-c(1,2,3,4,5,60)
rolls<-expand.grid(die,die)
## 返回两个骰子所有的可能(36种),如果有必要刻意处理更多向量prob<-c("1"=1/8,"2"=1/8,"3"=1/8,"4"=1/8,"5"=1/8,"6"=3/8)

n个独立随机事件同时发生的概率等于每个随机事件单独发生的概率的乘积.

die<-c(1,2,3,4,5,6)
rolls<-expand.grid(die,die)
rolls
rolls$value<-rolls$Var1+rolls$Var2
head(rolls,3)
# 骰子各点数对应概率
prob<-c("1"=1/8,"2"=1/8,"3"=1/8,"4"=1/8,"5"=1/8,"6"=3/8)
rolls$prob1<-prob[rolls$Var1]
head(rolls,3)
rolls$prob2<-prob[rolls$Var2]
head(rolls,3)
rolls$prob<-rolls$prob1*rolls$prob2
head(rolls,3)##=============结果===========Var1 Var2 value prob1 prob2     prob
1    1    1     2 0.125 0.125 0.015625
2    2    1     3 0.125 0.125 0.015625
3    3    1     4 0.125 0.125 0.015625

老虎机期望值步骤

  1. 列出所有可能结果
  2. 计算各组合出现的概率
  3. 确定每个符号对应的金额
wheel<-c("DD","7","BBB","BB","B","C","0")
prob=c("DD"=0.03,"7"=0.03,"BBB"=0.06,"BB"=0.1,"B"=0.25,"C"=0.01,"0"=0.52)
# stringAsFactors=FALSE 防止R将其转为因子导致报错
combos<-expand.grid(wheel,wheel,wheel,stringAsFactors=FALSE)
combos$prob1<-prob[combos$Var1]
combos$prob2<-prob[combos$Var2]
combos$prob3<-prob[combos$Var3]
combos$prob<-combos$prob1*combos$prob2*combos$prob3
head(combos,3)

9.3 循环

for(var in that){# ...
}for(value in c("My","first","for","loop")){}

注意: 如果循环使用了该环境已存在的对象名称,循环将使用它创建的对象覆盖当前环境中已存在的对象.

针对集合运行for循环

R的for循环不是针对整数序列运行,而是针对一个集合.

# while循环
while(condition){# ...
}# repeat循环
repeat{    if(condition){break}
}

10. 代码提速

10.1 向量化代码

快速的R代码有三个重点

  • 逻辑测试
  • 取子集
  • 元素方式执行

用到这三点的R代码一般都是向量化的.

向量化指代码可以接受一个含多个值的向量作为输入,并且同时操作向量中的每一个元素.

abs_loop<-function(vec){for(i in 1:length(vec)){if(vec[i]<0){vec[i]<- -vec[i]}}vec
}# 这个是abs_loop向量化版本
abs_set<-function(vec){negs<-vec<0vec[negs]<-vec[negs]*-1vec
}long<-rep(c(-1,1),5000000)system.time(abs_loop(long))
system.time(abs_set(long))

system.time测量用时

Sys.time返回当前系统时间

abs() R自带的求绝对值函数

有序步骤用向量化函数完成

同类情况,使用逻辑值取子集方式处理,一次性处理完成一类情况所有元素

<-是向量化的

vec<-c("DD","7","BBB","BB","B","C","0")
# 需要优化的代码
change_symbols<-function(vec){for(i in 1:length(vec)){if(vec[i]=="DD"){vec[i]<- "joker"} else if(vec[i]=="C"){vec[i]<- "ace"} else if(vec[i]=="7"){vec[i]<- "king"} else if(vec[i]=="B"){vec[i]<- "queen"} else if(vec[i]=="BB"){vec[i]<- "jack"} else if(vec[i]=="BBB"){vec[i]<- "ten"} else {vec[i]<- "nine"}}vec
}
change_symbols(vec)# 优化成向量
change_symbols<-function(vec){tb<-c("DD"="joker","7"="king","BBB"="ten","BB"="jack","B"="queen","C"="ace","0"="nine")                 unname(tb[vec])
}
change_symbols(vec)

其他语言有的需要编译,编译的过程会对代码的for循环针对计算机内存的使用进行优化,使for循环的速度非常快.而R中没有代码编译这一步.

任何语言编程,都应该利用该语言中运行速度最快的功能.

if,for

if与for组合出现的地方经常可以用逻辑值取子集操作替代,后者速度更快.

确保用来出处循环输出结果的对象必须具备足够的容量,以容纳循环的所有结果.不然每次循环都要调整对象的长度延长1,N此循环要重复N次的(复制向量,删除旧版本向量,找新地方存放向量的新版本)操作

源码中的 .Primitive, .Internal, .Call等,一般调用了使用其他语言编写的代码,可以获得外部语言带来的速度优势.

10.4 向量化编程实战

get_many_symbols<-function(n){wheel<-c("DD","7","BBB","BB","B","C","0")vec=sample(wheel,size=3*n,replace=TRUE,prob=c(0.03,0.03,0.06,0.1,0.25,0.01,0.52))matrix(vec,ncol=3)
}play_many<-function(n){symb_mat<-get_many_symbols(n=n)data.frame(w1=symb_mat[,1],w2=symb_mat[,2],w3=symb_mat[,3],prize=score_many(symb_mat))
}score_many<-function(symbols){# 根据樱桃和钻石的出现分配基础金额  cherries<-rowSums(symbols=="C")diamonds<-rowSums(symbols=="DD")prize<-c(0,2,5)[cherries+diamonds+1]prize[! cherries]<-0# 三个相同符号same<-symbols[,1]==symbols[,2]&symbols[,2]==symbols[,3]payoffs<-c("DD"==100,"7"=80,"BBB"=40,"BB"=25,"B"=10,"C"=10,"0"=0)prize[same]<-payoffs[symbols[same,1]]# 当符号组合都是杠bars<-symbols=="B"|symbols=="BB"|symbols=="BBB"all_bars<-bars[,1]&bars[,2]&bars[,3]&! sameprize[all_bars]<-5# 当两个钻石two_wilds<-diamonds==2one<-two_wilds&symbols[,1]!=symbols[,2]&symbols[,2]==symbols[,3]two<-two_wilds&symbols[,1]!=symbols[,2]&symbols[,1]==symbols[,3]three<-two_wilds&symbols[,1]==symbols[,2]&symbols[,2]!=symbols[,3]prize[one]<-payoffs[symbols[one,1]]prize[two]<-payoffs[symbols[two,2]]prize[three]<-payoffs[symbols[three,3]]# 当有一个钻石one_wild<-diamonds==1wild_bars<-one_wild&(rowSums(bars)==2)prize[wild_bars]<-5one<-one_wild&symbols[,1]==symbols[,2]two<-one_wild&symbols[,2]==symbols[,3]three<-one_wild&symbols[,3]==symbols[,1]prize[one]<-payoffs[symbols[one,1]]prize[two]<-payoffs[symbols[two,2]]prize[three]<-payoffs[symbols[three,3]]# 根据组合中出现的钻石个数,加倍奖金值unname(prize*2^diamonds)
}
system.time(play_many(10000000))

有些任务无法被向量化,具体情况具体分析

编程很大程度上与创造力,解决问题的能力,以及类似任务的编程经验相关.

10.6 总结

数据科学

  • 如何存储和操作数据时不犯错(物流)
  • 如何发现数据包含的信息(战术)
  • 如何利用数据引申对于数据外部世界的认识(战略)

学会R编程就掌握了解决物流问题的技巧,是解决战术和战略问题的前提.

进一步学习可看<<R for Data Science>>(中文译版 <<R数据科学>>)

http://www.rstudio.com/ide 免费下载RStudio

附录

R基础包是默认加载的函数,不需要加载任何R包就可以使用.

安裝R包:

install.packages(“包名称”)

install.packages(c(“包名称1”,“包名称2”))

更新:

update.packages(c(“ggplot2”,'reshape2",“dplyr”))

更新后关闭当前会话打开新会话才会生效

Austria镜像站点是CRAN存放包的主库.

devtools提供install_github,install_gitorious,install_bitbucket,install_url等

工作目录

getwd()

setwd("~/Users/…")

加载纯文本

read.table(“poker.csv”,sep=",",header=TRUE)

  • sep 告诉read.table我的文件使用的分隔符.

  • header 告诉读取文件时将第一行数据视为变量名称,而不是值.

  • na.strings 告诉函数,数据集中用什么表示缺失信息的.

  • skipg 告诉R在读取数据文件时忽略文件开头的一些行.

  • nrow 告诉R在读取某个数量的数据行之后就不再继续读取.

  • stringsAsFactors

read.table

read.csv

read.delim

read.csv2

read.delim2

read.fwf

后缀为.fwf是固定宽度文件(fixed-width file)

<<R语言入门与实践>>读书笔记相关推荐

  1. 读书笔记 | 墨菲定律

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  2. 读书笔记 | 墨菲定律(一)

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  3. 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记

    <洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...

  4. 股神大家了解多少?深度剖析股神巴菲特

    股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...

  5. 2014巴菲特股东大会及巴菲特创业分享

     沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...

  6. 《成为沃伦·巴菲特》笔记与感想

    本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...

  7. 读书笔记002:托尼.巴赞之快速阅读

    读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...

  8. 读书笔记001:托尼.巴赞之开动大脑

    读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...

  9. 读书笔记003:托尼.巴赞之思维导图

    读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...

  10. 产品读书《滚雪球:巴菲特和他的财富人生》

    作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...

最新文章

  1. Verilog设计实例(3)基于Verilog的单端口同步读写RAM设计
  2. 前端一HTML:十一:其他选择器
  3. RH5.4下安装samba服务器(1)
  4. NetBeans 时事通讯(刊号 # 60 - Jun 21, 2009)
  5. 注册表文件(*.reg)的编写及应用
  6. linux下.a/.so/.la目标库区别
  7. 【转】mip-semi-fixed 走走又停停
  8. centOS安装openoffice的方法
  9. 数据治理的好处有哪些
  10. axure 8 表格合并_多人编辑,自动汇总,领导可见所有?用 SeaTable 表格更简单
  11. 让 Edit 只接受数字《转》
  12. 半导体物理学习整理(一)
  13. trainNetwork - Matlab官网介绍的中文版
  14. 2017cad光标大小怎么调_把cad光标变大的方法步骤详解
  15. mysqldump导出数据备份 --set-gtid-purged=OFF(简明!!)
  16. Python tkinter改变光标样式
  17. swing的maven项目打成jar包
  18. 2.matlab图像三种方法灰度值处理
  19. Visual Paradigm 里什么是复合结构图?
  20. 3Dmax使用者快速上手Maya心得之建模

热门文章

  1. 前端开发和后端开发那个更有优势?
  2. 基于LeNet5的手写数字识别,在ModelArts和GPU上复现
  3. 程序帝国四大操作之单表修改
  4. CORS请求未能成功
  5. 使用库函数sqrt求平方根 C语言入门
  6. 文件批量重命名怎么做?几个简单办法在这里
  7. 第三方登录-wechat
  8. 电子版寸照可以在手机上修改底色吗
  9. flutter 图标演示
  10. ascii字体和GBK字体