前言
最近去codewars做了一点编程题,虽然都是一些很基础的题目,但是R语言并非类似C等较为底层的语言,在使用中没有必要重复造轮子。我认为更不能在使用中以重复造轮子为乐,虽然一些基础的操作是练习编程的好习题,但是在R中,往往有直接的函数来达成这些效果。所以我准备记录一些在学习中用到的轮子,尤其是base
包中的函数,这对于我这种半吊子上手R直接就去应用的人来说尤为有用。
正文
比较两个向量是否相等
all(..., na.rm = FALSE)
接受任意个逻辑型向量作为参数,返回TRUE
如果向量全为TRUE
,反之则返回FALSE
,参数na.rm = TRUE
时忽略向量中的NA
。如果传入的参数为空向量或者未传入参数,返回的结果都是TRUE
,这样保证了all(all(x),all(y)) == all(x,y)
即使x
是空向量(来自官方文档)。
any(..., na.rm = FALSE)
是类似的,区别是函数返回TRUE
如果向量中至少一个值为TRUE
,反之返回FALSE
。如果参数为空向量也会返回FALSE
。
在我想要判断两个向量是否相等时,例如x
和y
,我了解到可以使用all(x == y)
来判断,注意如果在if
语句中使用(x == y) == rep(TRUE, length(x))
,只会按照向量的第一个值进行比较判断。
再之后,我又了解到可以使用identical()
函数进行判断,idential(x,y)
判断时严格的,严格比较两个变量是否完全相等,包括数据类型,例如identical(1, as.integer(1))
会返回FALSE
。其它参数可以参见文档。
如果要求放低,还可以使用all.equal()
函数,这里函数不会比较变量的数据类型,同时允许变量间有一定的小差别,通过tolerance
参数来调节,默认为1.5e-8
。all.equal()
只有在相等时返回TRUE
,否则则会返回对于差距的描述,因此在使用时应当使用isTrue(all.equal(x,y))
。其它参数参见文档。
下面是几个实例。
x <- c(1,2); y <- c(1,3)
if(all(x == y)) print(TRUE)
if((x == y) == rep(TRUE, length(x))) print(TRUE)
## Warning in if ((x == y) == rep(TRUE, length(x))) print(TRUE): 条件的长度大于一,
## 因此只能用其第一元素
## [1] TRUE
#identical函数
x <- c(1,2); y <- c(1,2); z <- c(1, 2)
identical(x, y)
## [1] TRUE
identical(x, z)
## [1] TRUE
identical(1, as,integer(1))
## [1] FALSE
#all.equal函数
x <- c(1, 2); y <- c(1.1, 1.9)
all.equal(x, y, tolerance = 0.2)
## [1] TRUE
all.equal(1, as.integer(1))
## [1] TRUE
计算累计和
给定一个长度为n
的数组,计算其前k
项和,其中1<=k<=n
。我曾在一个帖子(统计之都上的帖子,不过我现在找不到了)看到,众多大佬说R语言几乎所有问题都可以避免使用for
语句,并且减少使用for
语句可以有效减少运行时间。于是我突发奇想,使用一个下三角矩阵和数组做矩阵乘法,并自以为很高明,直到计算一个较大的数组时提示内存溢出——生成的矩阵太大了。
cumsum()
就是求累计和的一个函数,它返回和原向量相同长度的向量,其第k
项为原数组前k
项和。类似的函数还有cumprod()
,cummax()
,cummin()
。我通过一定的方法找到了函数的源代码,发现源代码是由C书写的,使用的是递推的方法。
static SEXP cumsum(SEXP x, SEXP s)
{
LDOUBLE sum = 0.;
double *rx = REAL(x), *rs = REAL(s);
for (R_xlen_t i = 0 ; i < XLENGTH(x) ; i++) {
sum += rx[i]; /* NA and NaN propagated */
rs[i] = (double) sum;
}
return s;
}
如果要从最后开始求和,可以使用rev()
将数组倒序之后再使用cumsum()
函数。
字母表
C和C++里可以将英文字母转化为ASCII码进行运算,R里则不用那么麻烦。LETTERS
和letters
两个内置变量分别存储了大写英文字母和小写英文字母,对于字母的类似运算,可以使用match()
函数将字母转化为数字再进行运算。
值得一提的是R里还有几个内置变量month.abb
,month.name
和pi
,分别记录了月份的英文缩写,月份的英文名和\(\pi\)的值。
后记
越写越觉得这些东西太基础了,可是我可能使用过不少高级的包,却对基础的base
包中的函数仍然不清楚,学习这些可以减少编程时的卡壳,对于真正着眼于解决实际问题很有帮助。