R语言学习笔记(1)

GUTUN

2020/07/09

前言

最近去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
在我想要判断两个向量是否相等时,例如xy,我了解到可以使用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-8all.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里则不用那么麻烦。LETTERSletters两个内置变量分别存储了大写英文字母和小写英文字母,对于字母的类似运算,可以使用match()函数将字母转化为数字再进行运算。
值得一提的是R里还有几个内置变量month.abbmonth.namepi,分别记录了月份的英文缩写,月份的英文名和\(\pi\)的值。

后记

越写越觉得这些东西太基础了,可是我可能使用过不少高级的包,却对基础的base包中的函数仍然不清楚,学习这些可以减少编程时的卡壳,对于真正着眼于解决实际问题很有帮助。