R data.frame:为列中下一个值更改创建计数器的有效方法

时间:2018-02-21 10:41:57

标签: r dataframe

矢量A:

a = c(0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1)

向量B :(仅用于初始化)

b = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

数据帧:

dft <- data.frame(a,b)

下面的for循环比较每行“i”的值A [i]和向量A中的A [i + 1]。 如果i + 1不同 - >写“计数” 否则检查i + 2并增加“count”......

我们的想法是知道每一行的行数,直到A中的值发生变化。

count = 0

%需要无穷无尽(对于大型集合)但是能够完成其工作

for(i in 1:nrow(dft)) {
    for(j in i+1:nrow(dft)-1) {
        j_value <- dft[j,"a"]
        i_value <- dft[i,"a"]
        if (!is.na(j_value) & !is.na(i_value)){
            tmp_value <- abs(i_value - j_value)
            if(tmp_value > 0) {
               dft[i,"b"] <- count
               count = 0
               break
            } else {
                count = count + 1
            }
        }
    }
}

结果应该是:

    b
 1: 5
 2: 4
 3: 3
 4: 2
 5: 1
 6: 1
 7: 2
 8: 1
 9: 3
10: 2
11: 1
12: 5
13: 4
14: 3
15: 2
16: 1
17: 0

3 个答案:

答案 0 :(得分:2)

以下内容应该有效:

b = rle(a)
unlist(mapply(":", b$lengths, 1))
# [1] 5 4 3 2 1 1 2 1 3 2 1 5 4 3 2 1 1

或者在一行中:

with(rle(a), unlist(Map(":", lengths, 1)))

使用“data.table”,您可以执行以下操作:

library(data.table)
data.table(a)[, b := .N:1, rleid(a)][]
#     a b
#  1: 0 5
#  2: 0 4
#  3: 0 3
#  4: 0 2
#  5: 0 1
#  6: 1 1
#  7: 0 2
#  8: 0 1
#  9: 1 3
# 10: 1 2
# 11: 1 1
# 12: 0 5
# 13: 0 4
# 14: 0 3
# 15: 0 2
# 16: 0 1
# 17: 1 1

答案 1 :(得分:1)

使用data.table如何做到这一点。有一些反向排序,并使用shift将值与后续值进行比较。它可能有点复杂,但似乎有效。

library( data.table )
dft <- data.table(a)
dft[ , f := shift( a, 1L, fill = F, type = "lead" ) != a
     ][ .N:1, b := seq_len(.N), by = cumsum(f)
     ][ , f := NULL ]
dft

    a b
 1: 0 5
 2: 0 4
 3: 0 3
 4: 0 2
 5: 0 1
 6: 1 1
 7: 0 2
 8: 0 1
 9: 1 3
10: 1 2
11: 1 1
12: 0 5
13: 0 4
14: 0 3
15: 0 2
16: 0 1
17: 1 1

答案 2 :(得分:0)

以下是适用的另一种方法:

# The data
a=c(0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1)

# An index of the data
ind <- 1:length(a)

# The function to apply 

f <- function(x){ifelse(!is.na(which(a[x]!=a[x:length(a)])[1] - 1), # Check if we are in the last group before series ends
                        which(a[x]!=a[x:length(a)])[1] - 1, # if not return distance to nearest value change
                        ind[length(a)] - x + 1) # if we are return length of last block of values
  }

unlist(lapply(ind, f)) # Apply and unlist to vector
#>  [1] 5 4 3 2 1 1 2 1 3 2 1 5 4 3 2 1 1

如果您希望将其减少到which()语句,在这种情况下,最后一块同质值将被赋予NA。根据上下文的不同,您可能需要使用不同的方法来处理最后一个块,因为重复值的重复次数会被审查(可能您希望在ifelse的第二项中提供字符串,如'1+')。