6.22 寻找唯一值序列

6.22.1 问题

你需要找到一个向量或者因子的唯一值。

6.22.2 方案

你可以通过在向量里迭代寻找唯一值,但这样做在 R 里是很慢的。一个比较快的方案是通过 rle() 函数:

  1. # 示例数据
  2. v <- c("A", "A", "A", "B", "B", "B", "B", NA, NA, "C", "C",
  3. "B", "C", "C", "C")
  4. v
  5. #> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
  6. #> [13] "C" "C" "C"
  7. vr <- rle(v)
  8. vr
  9. #> Run Length Encoding
  10. #> lengths: int [1:7] 3 4 1 1 2 1 3
  11. #> values : chr [1:7] "A" "B" NA NA "C" "B" "C"

RLE 编码的数据能够通过 inverse.rle() 转换回到一个向量。

  1. inverse.rle(vr)
  2. #> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
  3. #> [13] "C" "C" "C"

一个问题是每一个缺失值 NA 都会视为长度为1,即使 NA 是相邻的,不过可以通过用别的值替代 NA 来做到。对于数值变量,Inf 或者别的数字都可使用;对于字符变量,任何字符串都能使用。当然,特殊值不得以其他方式出现在向量中。

  1. w <- v
  2. w[is.na(w)] <- "ZZZ"
  3. w
  4. #> [1] "A" "A" "A" "B" "B" "B" "B" "ZZZ"
  5. #> [9] "ZZZ" "C" "C" "B" "C" "C" "C"
  6. wr <- rle(w)
  7. wr
  8. #> Run Length Encoding
  9. #> lengths: int [1:6] 3 4 2 2 1 3
  10. #> values : chr [1:6] "A" "B" "ZZZ" "C" "B" "C"
  11. # 在RLE编码数据中用NA代替ZZZ
  12. wr$values[wr$values == "ZZZ"] <- NA
  13. wr
  14. #> Run Length Encoding
  15. #> lengths: int [1:6] 3 4 2 2 1 3
  16. #> values : chr [1:6] "A" "B" NA "C" "B" "C"
  17. w2 <- inverse.rle(wr)
  18. w2
  19. #> [1] "A" "A" "A" "B" "B" "B" "B" NA NA "C" "C" "B"
  20. #> [13] "C" "C" "C"

6.22.3 处理因子

虽然因子基本上只是带有一些关于级别信息的整数向量,但是 rle() 函数不能处理因子。解决方案是手动将因子转换为整数向量或字符向量。使用整数向量速度快,内存效率高,这对于大型数据集可能很重要,但是很难理解。使用字符向量比较慢,需要更多的内存,但是更容易理解。

  1. # 假设这是我们要处理的向量
  2. f <- factor(v)
  3. f
  4. #> [1] A A A B B B B <NA> <NA> C
  5. #> [11] C B C C C
  6. #> Levels: A B C
  7. # 将向量级别保存到一个新的变量
  8. # 这个不是必须的,但是保存顺序是很有用的
  9. f_levels <- levels(f)
  10. f_levels
  11. #> [1] "A" "B" "C"
  12. fc <- as.character(f)
  13. fc[is.na(fc)] <- "ZZZ"
  14. fc
  15. #> [1] "A" "A" "A" "B" "B" "B" "B" "ZZZ"
  16. #> [9] "ZZZ" "C" "C" "B" "C" "C" "C"
  17. fr <- rle(fc)
  18. fr
  19. #> Run Length Encoding
  20. #> lengths: int [1:6] 3 4 2 2 1 3
  21. #> values : chr [1:6] "A" "B" "ZZZ" "C" "B" "C"
  22. # 在RLE编码数据中用 NA 代替 ZZZ
  23. fr$values[fr$values == "ZZZ"] <- NA
  24. fr
  25. #> Run Length Encoding
  26. #> lengths: int [1:6] 3 4 2 2 1 3
  27. #> values : chr [1:6] "A" "B" NA "C" "B" "C"
  28. # 将RLE编码数据转换成因子
  29. f2 <- inverse.rle(fr)
  30. f2 <- factor(f, levels = f_levels)
  31. f2
  32. #> [1] A A A B B B B <NA> <NA> C
  33. #> [11] C B C C C
  34. #> Levels: A B C