本文已参加「新人创作礼」活动,一起开启掘金创作之路。
这次带来的是 RStudio 的常用运算函数。
各个知识点后面都有对应的小练习哦,大家可以利用刚刚学到的知识来试着写写看!
The apply family 使用apply系列函数
在很多需要用到循环的场景中, 特别是for循环中, 我们经常会对一个向量/列表/矩阵中的所有元素做同样的操作. 这种情况下, 我们可以使用apply family中的函数来替代循环的写法, 这可以使得代码更加紧凑.
apply family的核心函数是: apply, tapply 和 lapply, 后者的一些变体有 sapply, vapply, replicate.
- apply 的使用场景
- apply 的 MARGIN
- rowSums, colSums, rowMeans, colMeans
- tapply 的使用场景
- 配合gl或rep
- lapply 的使用场景
- 变体 sapply
- 变体 replicate
# apply 的使用场景: Apply Functions Over Array Margins
# Returns a vector or array or list of values obtained by applying a function to margins of an array or matrix.
# apply(X, MARGIN, FUN, ...)
dat1 = matrix(1:12, nrow=4)
dat1
apply(dat1, 1, sum)
# apply 的 MARGIN
apply(dat1, 1, sum)
apply(dat1, 2, sum)
dat2 = array(1:24, dim=c(4,3,2))
dat2
apply(dat2, 1, sum)
sum(dat2[1,,])
sum(dat2[2,,])
sum(dat2[3,,])
sum(dat2[4,,])
apply(dat2, 3, sum)
sum(dat2[,,1])
sum(dat2[,,2])
apply(dat1, c(1,2), sum)
apply(dat2, c(1,2), sum)
dat2[1,1,]
dat2[1,2,]
dat2[1,3,]
# rowSums, colSums, rowMeans, colMeans
# 对于最常见的二维数据, 比如矩阵和数据框, 经常需要按行或者按列求和/均值
# 这种情况下, R提供了更方便的函数
rowSums(dat1)
colSums(dat1)
rowMeans(dat1)
colMeans(dat1)
rowSums(dat2)
apply(dat2, 1, sum) # 等价于这个写法
colSums(dat2)
apply(dat2, 2, sum) # ??
apply(dat2, c(2,3), sum) # 等价于这个写法, 尽量避免在高维对象中使用rowSums,colSums等
# tapply 的使用场景
# Apply a function to each cell of a ragged array, that is to each (non-empty) group of values given by a unique combination of the levels of certain factors.
# tapply(X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
v1 = 1:6
v2 = c(1,2,1,2,1,2)
tapply(v1, v2, sum)
# Q: 数据集mtcars中不同气缸数的车的平均mpg是多少?
mean(mtcars$mpg[mtcars$cyl==4])
mean(mtcars$mpg[mtcars$cyl==6])
mean(mtcars$mpg[mtcars$cyl==8])
tapply(mtcars$mpg, mtcars$cyl, mean)
# 配合gl或rep
# gl(n, k, length = n * k, labels = seq_len(n), ordered = FALSE)
gl(3, 2)
rep(1:3, each=2) # 注意一个是因子型, 一个是数值型
gl(3, 2, 10)
# lapply 的使用场景: Apply a Function over a List or Vector
# lapply returns a list of the same length as X, each element of which is the result of applying FUN to the corresponding element of X.
# lapply(X, FUN, ...)
v3 = list(a = 1:10, b = 1:100, c = c(1,2,3,NA))
lapply(v3, sum) # 列表中每一个元素(子列表)的总和
f1 = function(x) length(x)
lapply(v3, f1) # 列表中每一个元素(子列表)的长度
lapply(v3, function(x) length(x))
# 当lapply所调用的函数需要设置参数的时候
lapply(v3, sum, na.rm=TRUE) # 列表中每一个元素(子列表)的总和(不包括NA项)
# 变体 sapply
# sapply is a user-friendly version and wrapper of lapply by default returning a vector, matrix or, if simplify = "array", an array if appropriate
# sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
sapply(v3, sum)
sapply(v3, sum, na.rm=T)
# sapply 和 lapply 经常被用来替代 for 循环
sapply(1:10, function(x) ifelse(x %% 2 == 0, x/2, 3*x+1))
# Q: 思考一下, 相对于 for LOOP, 这个sapply的写法节约了哪些步骤?
# 变体 replicate
# replicate is a wrapper for the common use of sapply for repeated evaluation of an expression (which will usually involve random number generation).
# replicate(n, expr, simplify = "array")
# 这个函数常常用来生成一些比较复杂的随机数, 或者重复一些模拟流程
小练习
# ------ 重新考虑我们曾做过的题目, 用lapply和sapply改写 ------------
# Q1:
# 对于不超过10000的所有正整数, 不打印, 记录每个数的Collatz Sequence.
# hint: 思考用何种数据结构来记录
# Q2:
# 接上题, 不超过10000的所有正整数中, 哪个数具有最长的Collatz Sequence, 长度是多少? 并打印出这个序列
# ------------------------------------------------------------------
习题
# Q1:
# 数据集 mtcars 中, 每个指标的均值是多少?
# Q2:
# 数据集 mtcars 中, 不同气缸数的车的平均重量(wt)是多少?
# Q3:
# 马力(hp)和车重(wt)可以大致决定一辆车的加速性能, 假设我们定义一个指标"hppp, 代表每单位车重所分配到的马力(HorsePower per Pound)", 那么, 请计算数据集 mtcars 中, 不同气缸数的车的平均hppp是多少?
# Q4:
# 在Q1中我们对于所有车计算了每个指标的均值, 在Q2中我们针对不同气缸数的车计算了一个指标的均值, 现在我们想针对不同气缸数的车计算每一个指标的均值, 思考如何完成这项任务.
Useful functions in math 常用的数学函数
elementary math
- min, max,
- which.min, which.max
- sum, prod, var, sd
- mean, median, quantile
- cumsum, cumprod, cummin, cummax
- sqrt, abs,
- round, floor, ceiling
- exp, log, log10
- sin, cos, tan, asin, acos, atan
- factorial
- choose
- table
set operation
- union
- intersect
- setdiff
- setequal
- %in%
- match
# cumsum(x)
cumsum(1:10)
# round, floor, ceiling
round(0.51)
floor(0.51)
ceiling(0.51)
# choose(n, k)
choose(10, 2)
# table(...)
table(c(5,4,5,3,5,2))
table(x=c(1,2,1,1), y=c("a","a","b","b"))
# union(x, y)
union(1:3, 2:5)
# intersect(x, y)
intersect(1:3, 2:5)
# setdiff(x, y)
setdiff(1:3, 2:5)
setdiff(2:5, 1:3)
# setequal(x, y)
setequal(1:3, 2:5)
setequal(1:3, 3:1)
# %in%
1 %in% 1:3
1 %in% 2:5
"a" %in% letters
"aa" %in% letters
# match(x, table, nomatch = NA_integer_, incomparables = NULL)
match(c("z", "o", "o"), letters)
match(c("zoo"), letters)
strsplit("apple", split="")
match(strsplit("apple", split="")[[1]], letters)
Useful functions in sampling & Simulation 常用的抽样函数&模拟运算
random sampling
- sample 简单随机抽样
- 随机数种子
- rbinom 基于二项分布的抽样
- rpois 基于泊松分布的抽样
- rexp 基于指数分布的抽样
- runif 基于均匀分布的抽样
- rnorm 基于正态分布的抽样
# sample 随机抽样
# sample(x, size, replace = FALSE, prob = NULL)
# x: 所有可选对象
# size: 样本数
# replace: 是否可放回(重复抽样)
# prob: 各个可选对象的出现概率
sample(1:30, 1)
sample(21:30, 2)
sample(1:5, 2)
sample(5, 3)
sample(5, 3, replace=TRUE)
sample(5, 3, prob=(1:5)/15)
# 设置随机数种子
set.seed(1)
sample(5, 3)
# rbinom(n, size, prob)
# n: 抽样次数
# size: (每一次的)样本数
# prob: 各个可选对象的出现概率
rbinom(10, 3, 0.5)
# rpois(n, lambda)
rpois(10, lambda=2)
# rexp(n, rate = 1)
rexp(10, rate=2)
# runif(n, min = 0, max = 1)
runif(10, 0, 100)
# rnorm(n, mean = 0, sd = 1)
rnorm(10, mean=80, sd=10)
round(rnorm(10, mean=80, sd=10))
# Q1
# 掷硬币模拟
# 一枚硬币, 扔10次, 出现至少7次正面的概率是多少?
# 这是一个简单的概率问题, 很容易得到解析解
rbinom(100, 10, 0.5)
table(rbinom(10000, 10, 0.5) >= 7)
# Q2
# 掷骰子模拟
# 掷两个骰子, 点数之和大于等于9的概率是多少?
sample(6, 2, replace=T)
dice = function(){
x = sample(6, 2, replace=T)
return(sum(x) >= 9)
}
dice()
table(replicate(100000, dice()))
# 更复杂的概率问题的模拟
# Q3
# 在[0,1]*[0,1]这个平面区域中随机选择一个点, 这个点落在以原点为圆心的单位圆内的概率是多少?
runif(2)
in_circle = function(){
distance = sum(runif(2)^2)
return(distance < 1)
}
N=10000
table(replicate(N, in_circle()))
table(replicate(N, in_circle()))/N
# 换一种写法
N=100000
mat = matrix(runif(2*N), ncol=2)
table(apply(mat, 1, function(x) sum(x^2)<1))
table(apply(mat, 1, function(x) sum(x^2)<1))/N
# 思考: 你能用上面的结果给出圆周率的一个估计值吗?
习题
# Q1
# 在[0,1]中随机取3个实数, 这三个实数两两之间的最小间距大于等于0.2的概率是多少?
# Q2
# 有4个小球, 3个盒子, 每个球都会随机的放入某一个盒子中, 问至少有一个盒子中出现两个小球的概率是多少?
# Q3
# 有4个小球, 3个盒子, 每个球都会随机的放入某一个盒子中, 问有且只有一个盒子中出现两个小球的概率是多少?