6.22 寻找唯一值序列

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