6.22 寻找唯一值序列
6.22.1 问题
你需要找到一个向量或者因子的唯一值。
6.22.2 方案
你可以通过在向量里迭代寻找唯一值,但这样做在 R 里是很慢的。一个比较快的方案是通过 rle()
函数:
# 示例数据
v <- c("A", "A", "A", "B", "B", "B", "B", NA, NA, "C", "C",
"B", "C", "C", "C")
v
#> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
#> [13] "C" "C" "C"
vr <- rle(v)
vr
#> Run Length Encoding
#> lengths: int [1:7] 3 4 1 1 2 1 3
#> values : chr [1:7] "A" "B" NA NA "C" "B" "C"
RLE 编码的数据能够通过 inverse.rle()
转换回到一个向量。
inverse.rle(vr)
#> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
#> [13] "C" "C" "C"
一个问题是每一个缺失值 NA
都会视为长度为1,即使 NA
是相邻的,不过可以通过用别的值替代 NA
来做到。对于数值变量,Inf
或者别的数字都可使用;对于字符变量,任何字符串都能使用。当然,特殊值不得以其他方式出现在向量中。
w <- v
w[is.na(w)] <- "ZZZ"
w
#> [1] "A" "A" "A" "B" "B" "B" "B" "ZZZ"
#> [9] "ZZZ" "C" "C" "B" "C" "C" "C"
wr <- rle(w)
wr
#> Run Length Encoding
#> lengths: int [1:6] 3 4 2 2 1 3
#> values : chr [1:6] "A" "B" "ZZZ" "C" "B" "C"
# 在RLE编码数据中用NA代替ZZZ
wr$values[wr$values == "ZZZ"] <- NA
wr
#> Run Length Encoding
#> lengths: int [1:6] 3 4 2 2 1 3
#> values : chr [1:6] "A" "B" NA "C" "B" "C"
w2 <- inverse.rle(wr)
w2
#> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
#> [13] "C" "C" "C"
6.22.3 处理因子
虽然因子基本上只是带有一些关于级别信息的整数向量,但是 rle()
函数不能处理因子。解决方案是手动将因子转换为整数向量或字符向量。使用整数向量速度快,内存效率高,这对于大型数据集可能很重要,但是很难理解。使用字符向量比较慢,需要更多的内存,但是更容易理解。
# 假设这是我们要处理的向量
f <- factor(v)
f
#> [1] A A A B B B B <NA> <NA> C
#> [11] C B C C C
#> Levels: A B C
# 将向量级别保存到一个新的变量
# 这个不是必须的,但是保存顺序是很有用的
f_levels <- levels(f)
f_levels
#> [1] "A" "B" "C"
fc <- as.character(f)
fc[is.na(fc)] <- "ZZZ"
fc
#> [1] "A" "A" "A" "B" "B" "B" "B" "ZZZ"
#> [9] "ZZZ" "C" "C" "B" "C" "C" "C"
fr <- rle(fc)
fr
#> Run Length Encoding
#> lengths: int [1:6] 3 4 2 2 1 3
#> values : chr [1:6] "A" "B" "ZZZ" "C" "B" "C"
# 在RLE编码数据中用 NA 代替 ZZZ
fr$values[fr$values == "ZZZ"] <- NA
fr
#> Run Length Encoding
#> lengths: int [1:6] 3 4 2 2 1 3
#> values : chr [1:6] "A" "B" NA "C" "B" "C"
# 将RLE编码数据转换成因子
f2 <- inverse.rle(fr)
f2 <- factor(f, levels = f_levels)
f2
#> [1] A A A B B B B <NA> <NA> C
#> [11] C B C C C
#> Levels: A B C