查找向量中最后一次出现的唯一元素的索引

Joa*_*mal 16 r

我有一个无序的向量v,如下所示,并希望找到列表中每个唯一元素的最后一个出现的索引.

v <- scan(text="1 2 1 2 1 1 1 3 1 2 2 3 3 3 1 1 1 4 1 1 1 4 1 5 5 6
                6 2 3 3 4 4 2 2 2 2 2 3 3 3 1 4 4 4 3 2 5 5 5 5")
v
# [1] 1 2 1 2 1 1 1 3 1 2 2 3 3 3 1 1 1 4 1 1 1 4 1 5 5 6 6 2 3 3 4 4 2 2 2 2 2 3 3 3 
# [41] 1 4 4 4 3 2 5 5 5 5
Run Code Online (Sandbox Code Playgroud)

预期结果(按1,2,3,4,5的顺序):

41 46 45 44 50
Run Code Online (Sandbox Code Playgroud)

我知道我可以unique(unlist(v))用来找到独特的元素但是如何找到它们最后一次出现的指数?任何的想法?

提前致谢.

nic*_*ola 17

即使数据未订购,另一种方法仍然有效:

length(v1)-match(unique(v1),rev(v1))+1
Run Code Online (Sandbox Code Playgroud)


Jos*_*ien 10

tapply(seq_along(v), v, max)
#  1  2  3  4  5  6 
# 41 46 45 44 50 27 
Run Code Online (Sandbox Code Playgroud)


akr*_*run 7

rle如果vector已经订购,您可以尝试.提取长度($lengths)然后cumsum.正如我之前提到的,如果它没有被排序,这将不起作用(再次取决于你真正想要的东西).基本上rle通过检查一段中相似的连续元素的数量来工作.它将在列表中给出lengths和对应values.

cumsum(rle(v1)$lengths)
#[1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

另一个选择是按向量对序列进行分组,并获取max每个序列的值group.我想这会很慢.

unname(cumsum(tapply(seq_along(v1),v1, FUN=which.max)))    
#[1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

或者只是检查前值是否相同的电流值,然后插入TRUE作为最后一个元素,并获得该指数TRUEwhich

 which(c(v1[-1]!=v1[-length(v1)],TRUE))
 #[1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

或者使用 match

 c(match(unique(v1),v1)-1, length(v1))[-1]
#[1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

或者使用 findInterval

 findInterval(unique(v1), v1)
 #[1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

更新

对于新的载体 v2

max.col(t(sapply(unique(v2), `==`, v2)),'last')
#[1] 41 46 45 44 50 27
Run Code Online (Sandbox Code Playgroud)

或者在无序向量findInterval之后使用的函数ordering

   f1 <- function(v){
      v1 <- setNames(v, seq_along(v))
      ind <- order(v1)
      as.numeric(names(v1[ind][findInterval(unique(v1), v1[ind])]))
    }     

 f1(v2)
 #[1] 41 46 45 44 50 27
Run Code Online (Sandbox Code Playgroud)

使用z@Marat talipov帖子中的例子(),

 f1(z)
 #[1] 4 5 3
Run Code Online (Sandbox Code Playgroud)

注意:我按照唯一元素首次出现的顺序得到结果z.即1,然后3,2.如果需要根据值再次订购,可以使用order(如@Marat Talipov所述).但是,目前尚不清楚OP在这种情况下真正想要的是什么.

数据

v1 <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 
 3, 4, 4, 4, 4, 5, 5, 5, 5)

v2 <-  c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1, 
 1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1, 
 4, 4, 4, 3, 2, 5, 5, 5, 5)

 z <- c(1, 3, 2, 1, 3)
Run Code Online (Sandbox Code Playgroud)

  • @jmkam当你发布一个例子时,最好是模仿数据,否则,有很多可能的场景,解决方案等. (3认同)

Dav*_*urg 6

也可以试试

which(c(diff(tmp), TRUE) == 1)
# [1] 28 37 42 46 50
Run Code Online (Sandbox Code Playgroud)

或者类似的

which(!!c(diff(tmp), TRUE))
Run Code Online (Sandbox Code Playgroud)


A5C*_*2T1 6

您可以尝试使用.N"data.table",如下所示:

library(data.table)
data.table(x, y = seq_along(x))[, y[.N], by = x]
#    x V1
# 1: 1 41
# 2: 2 46
# 3: 3 45
# 4: 4 44
# 5: 5 50
# 6: 6 27
Run Code Online (Sandbox Code Playgroud)

在这里,我们基本上创建了一个两列data.table,其中第一列是向量,第二列是向量的索引位置..N告诉我们每组中有多少行(捕获by =),因此我们可以y直接使用该信息对值进行子集化.


更好的是,正如@Arun所推荐的,我们可以跳过创建"y"并直接执行:

data.table(x)[, .I[.N], by=x]
Run Code Online (Sandbox Code Playgroud)

样本数据:

x <- c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1, 
  1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1, 
  4, 4, 4, 3, 2, 5, 5, 5, 5)
Run Code Online (Sandbox Code Playgroud)


Mar*_*pov 5

我很遗憾地说,但是接受的答案,以及应该对无序向量起作用的其他几个答案,提供了错误的解决方案.

[EDIT2]

这个答案已成为一个争议,应该被视为"正确"或"错误"的答案.在这里,我将所需的输出解释为解决方案应该是沿着独特元素的递增顺序排序的未命名向量.事实证明,其他解释可能存在(见下面的评论),虽然它们对我来说看起来不太明显,但它们肯定有权存在,至少在OP增加更多例子来澄清情况之前

从这个角度来看,最好再说"重现OP样本的答案可能导致其他输入数据集在输出向量中对元素的排序产生不一致的结果".这种不一致的部分原因在于原始OP的问题被改变了几次,并且在问题的当前状态下完全正确的答案可能对问题的最终状态不起作用.我的答案应该让读者了解这种情况,并提出简单的解决办法,以获得OP问题最终状态的解决方案.

最后,我确实认识到我的答案结果是一个巨大的矫枉过正,但鉴于帖子中的混乱程度,我认为最好澄清未来感兴趣的读者的情况.

/ [EDIT2]

当我开始将不同的解决方案放在一起进行基准研究时,我偶然发现了这个问题.这里提到的一些解决方案不起作用,因为原始问题暗示输入向量按递增顺序排序,事实证明并非如此,所以我不在这里讨论它们.为作者的示例数据集提供正确答案的解决方案被收集在一起并包含在相应的函数中:

f.duplicated <- function(z) {
  i <- which(!duplicated(z,fromLast=T))
  i[order(z[i])]  
}

f.match.unique.rev <- function(v1) {
  length(v1)-match(unique(v1),rev(v1))+1
}

f.max.col.sapply.unique <- function(v2){
  max.col(t(sapply(unique(v2), `==`, v2)),'last')
}

f.data.table <- function(x) {
  # data.table(x, y = seq_along(x))[, y[.N], by = x]$V1
  setkey(data.table(x, y = seq_along(x)), x)[, y[.N], by = x]$V1
}

f.tapply.seq_along.max <- function(v) {
  tapply(seq_along(v), v, max)
}

f.sapply.split.seq_along.max <- function(v) {
  sapply(split(seq_along(v), v), max)
}
Run Code Online (Sandbox Code Playgroud)

然后,我写了一个小函数来比较结果:

compare.results <- function(z) {
  d <- rbind(
    f.duplicated(z),
    f.match.unique.rev(z),
    f.max.col.sapply.unique(z),
    f.data.table(z),
    f.tapply.seq_along.max(z),
    f.sapply.split.seq_along.max(z)
    )
  rownames(d) <- c(
    'f.duplicated',
    'f.match.unique.rev',
    'f.max.col.sapply.unique',
    'f.data.table',
    'f.tapply.seq_along.max',
    'f.sapply.split.seq_along.max'
  )
  d
}
Run Code Online (Sandbox Code Playgroud)

并确保所选解决方案适用于示例性数据:

z <- c(1,2,1,2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1, 4, 4, 4, 3, 2, 5, 5, 5, 5)

compare.results(z)
#                               1  2  3  4  5  6
# f.duplicated                 41 46 45 44 50 27
# f.match.unique.rev           41 46 45 44 50 27
# f.max.col.sapply.unique      41 46 45 44 50 27
# f.data.table                 41 46 45 44 50 27
# f.tapply.seq_along.max       41 46 45 44 50 27
# f.sapply.split.seq_along.max 41 46 45 44 50 27
Run Code Online (Sandbox Code Playgroud)

[问题]当我使用另一个输入向量时1 3 2 1 3,正确答案是4 3 5,我发现某些解决方案提供了错误的结果:

z <- c(1,3,2,1,3)
compare.results(z)
#                              1 2 3
# f.duplicated                 4 3 5
# f.match.unique.rev           4 5 3  # ***
# f.max.col.sapply.unique      4 5 3  # ***
# f.data.table                 4 3 5
# f.tapply.seq_along.max       4 3 5
# f.sapply.split.seq_along.max 4 3 5
Run Code Online (Sandbox Code Playgroud)

[FIX]我发现f.match.unique.rev(接受的答案)和f.max.col.sapply.unique解决方案的问题在于暗示独特元素在数据集中具有递增的顺序,这在作者的示例中是这种情况,但在我的示例中没有.以下是固定的解决方案:

f.max.col.sapply.unique <- function(v2){
  i <- max.col(t(sapply(unique(v2), `==`, v2)),'last')
  i[order(v2[i])]  
}


f.match.unique.rev <- function(v1) {
  i <- length(v1)-match(unique(v1),rev(v1))+1
  i[order(v1[i])]  
}
Run Code Online (Sandbox Code Playgroud)

[编辑]我被告知原始f.data.table结果 - 这是一个带有两列(xV1)的data.table结构- 包含以问题作者所期望的格式构建答案所需的所有信息.事实上,f.data.table我决定使用列V1作为函数输出引入了错误.我f.data.table通过修改后的代码更新(请参阅下面的评论),以预期的格式提供正确的解决方案,并将旧版本保存为注释.此外,我f.data.table从答案的最后删除了对解决方案的讨论,因为它不再需要了.

  • 仅供参考,OP改变了他的数据并希望输出相当多次,而且我们没有义务每小时在这里办理登机手续以查看是否有新请求. (4认同)