可视化:RStudio 常用运算函数

840 阅读7分钟

本文已参加「新人创作礼」活动,一起开启掘金创作之路。

这次带来的是 RStudio 的常用运算函数。

各个知识点后面都有对应的小练习哦,大家可以利用刚刚学到的知识来试着写写看!

The apply family 使用apply系列函数

在很多需要用到循环的场景中, 特别是for循环中, 我们经常会对一个向量/列表/矩阵中的所有元素做同样的操作. 这种情况下, 我们可以使用apply family中的函数来替代循环的写法, 这可以使得代码更加紧凑.

apply family的核心函数是: applytapply 和 lapply, 后者的一些变体有 sapplyvapplyreplicate.

  • 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个盒子, 每个球都会随机的放入某一个盒子中, 问有且只有一个盒子中出现两个小球的概率是多少?