【问题标题】:Sequence length encoding using R使用 R 的序列长度编码
【发布时间】:2011-08-16 11:45:53
【问题描述】:

有没有办法在 R 中编码递增整数序列,类似于使用游程编码 (rle) 来编码游程长度?

我会用一个例子来说明:

类比:行程编码

r <- c(rep(1, 4), 2, 3, 4, rep(5, 5))
rle(r)
Run Length Encoding
  lengths: int [1:5] 4 1 1 1 5
  values : num [1:5] 1 2 3 4 5

要求:序列长度编码

s <- c(1:4, rep(5, 4), 6:9)
s
[1] 1 2 3 4 5 5 5 5 6 7 8 9

somefunction(s)
Sequence lengths
  lengths: int [1:4] 5 1 1 5
  value1 : num [1:4] 1 5 5 5

编辑 1

因此,somefunction(1:10) 将给出结果:

Sequence lengths
  lengths: int [1:1] 10
  value1 : num [1:1] 1 

这个结果意味着有一个长度为10的整数序列,起始值为1,即seq(1, 10)

请注意,我的示例结果中没有错误。该向量实际上以 5:9 的序列结束,而不是用于构建它的 6:9。

我的用例是我正在处理 SPSS 导出文件中的调查数据。问题网格中的每个子问题都会有一个模式名称paste("q", 1:5),但有时会有一个“其他”类别标记为q_99q_other 或其他内容。我希望找到一种识别序列的方法。

编辑 2

在某种程度上,我想要的函数是基函数 sequence 的逆函数,在我的示例中添加了起始值 value1

lengths <- c(5, 1, 1, 5)
value1 <- c(1, 5, 5, 5)

s
[1] 1 2 3 4 5 5 5 5 6 7 8 9
sequence(lengths) + rep(value1-1, lengths) 
[1] 1 2 3 4 5 5 5 5 6 7 8 9

编辑 3

我应该声明,就我的目的而言,序列被定义为递增整数序列,而不是单调递增序列,例如c(4,5,6,7) 但不是c(2,4,6,8) 也不是c(5,4,3,2,1)。但是,序列之间可以出现任何其他整数。

这意味着一个解决方案应该能够处理这个测试用例:

somefunction(c(2, 4, 1:4, 5, 5))
    Sequence lengths
      lengths: int [1:4] 1 1 5 1
      value1 : num [1:4] 2 4 1 5 

在理想情况下,该解决方案还可以处理最初建议的用例,其中包括向量中的字符,例如

somefunction(c(2, 4, 1:4, 5, "other"))
    Sequence lengths
      lengths: int [1:5] 1 1 5 1 1
      value1 : num [1:5] 2 4 1 5 "other"

【问题讨论】:

  • Andrie,我仍然不清楚您的序列编码是如何工作的。这些值来自哪里,长度意味着什么? +1 用于举例说明,但您可以使其更清晰。
  • 请定义:“序列”。 :) 我和 Ramnath 在一起——这不太合理。
  • @Ramnath 我希望编辑让它更清楚。在序列 1:10 中,长度为 10,value1 为 1。换句话说,您可以将这些参数传递给 seq.int 以重建原始向量。例如seq.int(1, lenght.out=10)
  • @Iterator。序列的定义与 R 中的 seq 函数相同。因此,1:5 是从 1 到 5 的整数序列,即 c(1,2,3,4,5)
  • 知道了。那么,这仅仅是决定何时在repseq 之间切换以重现给定向量的一种方式吗? (似乎rep 的默认复制为 1?)如果是这样,那么这是一个有趣的编码问题。

标签: r encoding


【解决方案1】:

编辑:添加了对字符向量的控制。

基于rle,我得出以下解决方案:

somefunction <- function(x){

    if(!is.numeric(x)) x <- as.numeric(x)
    n <- length(x)
    y <- x[-1L] != x[-n] + 1L
    i <- c(which(y|is.na(y)),n)

    list(
      lengths = diff(c(0L,i)),
      values = x[head(c(0L,i)+1L,-1L)]
    )

}

> s <- c(2,4,1:4, rep(5, 4), 6:9,4,4,4)

    > somefunction(s)
    $lengths
    [1] 1 1 5 1 1 5 1 1 1

    $values
    [1] 2 4 1 5 5 5 4 4 4

这个适用于我尝试过的每个测试用例,并使用没有 ifelse 子句的矢量化值。应该跑得更快。它将字符串转换为 NA,因此您可以保留数字输出。

> S <- c(4,2,1:5,5, "other" , "other",4:6,2)

> somefunction(S)
$lengths
[1] 1 1 5 1 1 1 3 1

$values
[1]  4  2  1  5 NA NA  4  2

Warning message:
In somefunction(S) : NAs introduced by coercion

【讨论】:

  • 为什么 2 和 4 被算作单独子序列的一部分?
  • 因为@Andrie 说在R 中使用: 定义了一个序列。并且 4 没有跟在 2 之后。
  • +1 矢量化 - 不错!事情应该是这样的。它甚至被称为somefunction。得去投票反对安德烈建议一个坏名字。开个玩笑。
【解决方案2】:

这是我的解决方案

diff_s = which(diff(s) != 1)
lengths = diff(c(0, diff_s, length(s)))
values  = s[c(1, diff_s + 1)]

编辑:也可以处理字符串

sle2 = function(s){
  s2 = as.numeric(s)
  s2[is.na(s2)] = 100 + as.numeric(factor(s[is.na(s2)]))
  diff_s2 = which(diff(s2) != 1)
  lengths = diff(c(0, diff_s2, length(s)))
  values  = s[c(1, diff_s2 + 1)]
  return(list(lengths = lengths, values = values))
}

sle2(c(4,2,1:5,5, "other" , "other",4:6,2, "someother", "someother"))

lengths
 [1] 1 1 5 1 1 1 3 1 1 1

$values
 [1] "4"   "2"  "1"   "5"  "other" "other"  "4"   "2"  "someother" "someother"

Warning message:
In sle2(c(4, 2, 1:5, 5, "other", "other", 4:6, 2, "someother", "someother")) :
  NAs introduced by coercion

【讨论】:

  • 尝试 s
  • 不。输出应该是 1 1 5 1 1 5 1 1 1 的长度,但它没有给出。 (请使用&lt;- 而不是= 进行作业。我知道两者都有效,但仍然......)
  • 不。这里是序列 (2, 4), (1, 2, 3, 4, 5), (5), (5), (5, 6, 7, 8, 9), (4), (4), (4) 长度为2, 5, 1, 1, 5, 1, 1, 1,起始值为2, 1, 5, 5, 5, 4, 4, 4
  • 我认为有一个问题是你指望在序列结束后有一个较小的数字。因此,您的长度不正确(例如):s &lt;- c(2,4,1:4, rep(5, 4), 6:9,12,4,11)
  • @尼克,乔里斯。这应该可以解决它,因为我现在对子序列有了更好的理解。
【解决方案3】:

你可以用这个作为开始(上面给你s):

s2<-c(0, diff(s))
s3<-ifelse((c(s2[-1], 0)==1) & (s2!=1), 1, s2)
rle(ifelse(s3==1, -1, seq_along(s3)))

它还没有返回值,可能有足够简单的方法来调整代码。至少您有序列长度,因此您可以轻松检索序列的起始值。

【讨论】:

  • 我认为这些值可能由s2 的非零元素的索引或s2 上的第二遍差异的索引引用。我仍然在思考最初的长度问题。这些价值观对我来说似乎更容易......
  • 这会给 c(2,4,1:4,5,5,...) 带来麻烦
【解决方案4】:

怎么样:

sle <- function(s)
{
    diffs <- which(diff(s)!=1)
    lengths <- c(diffs[1],diff(diffs),length(s)-diffs[length(diffs)])
    value1 <- s[c(1,diffs+1)]
    cat("", "Sequence Length Encoding\n", " lengths:")
    str(lengths)
    cat("  value1:")
    str(value1)
}


sle(s)
 Sequence Length Encoding
  lengths: int [1:4] 5 1 1 5
  value1: num [1:4] 1 5 5 5

sle(c(2,4,1:4,rep(5,4),6:9,4,4,4))
 Sequence Length Encoding
  lengths: int [1:9] 1 1 5 1 1 5 1 1 1
  value1: num [1:9] 2 4 1 5 5 5 4 4 4

【讨论】:

  • 为什么 2 和 4 被算作单独子序列的一部分?关键是如何确定子序列。我的假设是突破点是数字不增加的时候。你的是什么?
  • @Ramnath :因为它们都形成了长度为 1 的序列?
  • @Ramnath 我知道感兴趣的序列是连续的整数。
  • 这是我的初衷,所以您的解决方案符合我的预期。 @Ramnath,我已经编辑了我的问题以明确指定这一点。现在,对于一个额外的挑战,如何应对向量中的字符?
  • @Andrie 不要认为它适用于数字和字符的混合,但您始终可以将字符更改为负整数以突出显示它们。
【解决方案5】:

这是对 Joris Meys 解决方案的增强。考虑这是对未来问题的解决方案:-)。

卡尔

seqle <- function(x,incr=1) {
    if(!is.numeric(x)) x <- as.numeric(x)
    n <- length(x)
    #y <- x[-1L] != x[-n] + 1L
    y <- x[-1L] != x[-n] + incr
    i <- c(which(y|is.na(y)),n)
    list( lengths = diff(c(0L,i)),  values = x[head(c(0L,i)+1L,-1L)])
}

【讨论】:

  • 感谢 Ben,改进了格式。我应该自己做的。顺便说一句,如果人们不知道,这个和 Joris 的代码正是 base::rle 中的代码,在 y 的公式中添加了“+incr”偏移量。
【解决方案6】:

“我的用例是我正在处理 SPSS 导出文件中的调查数据。问题网格中的每个子问题都有一个模式 paste("q", 1:5) 的名称,但有时会有“其他”类别将被标记为 q_99、q_other 或其他内容。我希望找到一种识别序列的方法。

当我从 Confirmit、DASH、SPSS、SAS、MySQL 或其他任何东西中提取数据时,我通常会这样做,这取决于它总是被放入 data.frame() 的来源:

surv.pull <- function(dat, pattern) {
  dat <- data.frame(dat[,grep(pattern,colnames(dat))],check.names=F)
return(dat)
}

如果你像[q][_][9][9] 一样使用pattern,你可以通过添加“.”来决定是否拉取其他数据空间的data.frame。到最后[q][_][9][9].,以便它拉q_99whatever

我的大部分数据列都是这样的 q8a.1, .3, .4, .5, .6, .7, .8, ... 所以surv.pull(dat, "[q][8][a].") 会将它们全部提取出来,包括其他,如果有指定。显然,使用正则表达式你可以决定是否拉另一个。

另外,一般惯例是将其他指定问题推到数据空间的末尾,因此快速df &lt;- df[-ncol(df)] 将删除它或other_list &lt;- df[ncol(df)] 将保存它。

【讨论】:

  • 我对这个设计模式很熟悉,自己也用。这不是问题。我想要实现的是将初始序列与最后的任何“其他”列分开。因此,列名可以是c("q_1", "q_2", "q_3", "q_99", "q_99_other")。我的问题试图找到一种方法将 1:3 的初始序列与 99 分开。grep 模式不能轻易做到这一点。
  • 您总是可以用 colnames 中的另一个标识符替换 99。我通常在一开始就这样做,然后将它们推送到动词文件中以供以后查看。 .[9][9].(99 有时是我的另一个指定列)。除非 99 对您来说是一个实际的问题编号? (综合?)
  • 是的,但是如果它是“q_98”或其他任何东西怎么办。一般的模式是,开头可能有一个序列(有时是一个中断的序列),并且通常在结尾有一堆杂乱无章的“其他”问题,其中“其他”的编码不同,具体取决于小组/综合/实地调查供应商.我发现 98 或 99 通常是一个布尔值/数字,表示该选项已被勾选,其中“q_99_other”包含文本。
  • names(df[,sapply(df,!is.numeric)]) 将为您提供所有逐字列的列表。因此,您可能可以使用它来完全避免处理排序问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 2010-11-07
  • 2019-12-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多