列中的每个更改都会增加1

dim*_*_ps 7 r

假设我有以下数据框架

set.seed(123)
df <- data.frame(var1=(runif(10)>0.5)*1)
Run Code Online (Sandbox Code Playgroud)

var1 可以有任何类型/数量的级别,而不是具体的0和1

我想创建一个var2每次var1更改时增加1 而不使用afor loop

这种情况下的预期结果是:

data.frame(var1=(runif(10)>0.5)*1, var2=c(1, 2, 3, 4, 4, 5, 6, 6, 6, 7))

var1 var2
   0    1
   1    2
   0    3
   1    4
   1    4
   0    5
   1    6
   1    6
   1    6
   0    7
Run Code Online (Sandbox Code Playgroud)

数据框的另一个选择可能是:

df <- data.frame(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1"))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,结果应该是:

var1 var2
   a    1
   a    1
   1    2
   0    3
   b    4
   b    4
   b    4
   c    5
   1    6
   1    6
Run Code Online (Sandbox Code Playgroud)

cmb*_*rbu 11

以弗里克先生为基础回答:

df$var2 <- cumsum(c(0,as.numeric(diff(df$var1))!=0))
Run Code Online (Sandbox Code Playgroud)

但如果您不想使用,diff您仍然可以使用:

df$var2 <- c(0,cumsum(as.numeric(with(df,var1[1:(length(var1)-1)] != var1[2:length(var1)]))))
Run Code Online (Sandbox Code Playgroud)

它从0开始,而不是1,但我确定如果你愿意,你会看到如何改变它.


MrF*_*ick 10

如何使用diff()cumsum().例如

df$var2 <- cumsum(c(1,diff(df$var1)!=0))
Run Code Online (Sandbox Code Playgroud)


Mar*_*gan 8

这些看起来像一个游程编码(rle)

x = c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1")
r = rle(x)
Run Code Online (Sandbox Code Playgroud)

> rle(x)
Run Length Encoding
  lengths: int [1:6] 2 1 1 3 1 2
  values : chr [1:6] "a" "1" "0" "b" "c" "1"
Run Code Online (Sandbox Code Playgroud)

这表示第一个值("a")连续出现2次,然后"1"出现一次,等等.你要追求的是沿着'长度'创建一个序列,并复制序列的每个元素元素出现的次数,所以

> rep(seq_along(r$lengths), r$lengths)
 [1] 1 1 2 3 4 4 4 5 6 6
Run Code Online (Sandbox Code Playgroud)

其他答案是半欺骗性的,因为它们依赖于列是因子(); 当列实际上是一个字符()时它们会失败.

> diff(x)
Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] : 
  non-numeric argument to binary operator
Run Code Online (Sandbox Code Playgroud)

解决方法是将字符映射到整数,沿着线条

> diff(match(x, x))
[1]  0  2  1  1  0  0  3 -5  0
Run Code Online (Sandbox Code Playgroud)

嗯,但是我说我发现rle不适合因素!

> f = factor(x)
> rle(f)
Error in rle(factor(x)) : 'x' must be a vector of an atomic type
> rle(as.vector(f))
Run Length Encoding
  lengths: int [1:6] 2 1 1 3 1 2
  values : chr [1:6] "a" "1" "0" "b" "c" "1"
Run Code Online (Sandbox Code Playgroud)


mpe*_*tis 6

我只是复制rle()上面 Martin Morgan 的答案,但使用 tidyverse 约定来实现它,以便将分组列直接添加到数据框/tibble,这就是我大多数时候最终使用的方式。

## Using run-length-encoding, create groups of identical values and put that
## common grouping identifier into a `grp` column.
library(tidyverse)

set.seed(42)

df <- tibble(x = sample(c(0,1), size=20, replace=TRUE, prob = c(0.2, 0.8)))

df %>%
    mutate(grp = rle(x)$lengths %>% {rep(seq(length(.)), .)})
#> # A tibble: 20 x 2
#>        x   grp
#>    <dbl> <int>
#>  1     0     1
#>  2     0     1
#>  3     1     2
#>  4     0     3
#>  5     1     4
#>  6     1     4
#>  7     1     4
#>  8     1     4
#>  9     1     4
#> 10     1     4
#> 11     1     4
#> 12     1     4
#> 13     0     5
#> 14     1     6
#> 15     1     6
#> 16     0     7
#> 17     0     7
#> 18     1     8
#> 19     1     8
#> 20     1     8
Run Code Online (Sandbox Code Playgroud)


jog*_*ogo 5

这是使用 R 基数的另一种解决方案inverse.rle()

df <- data.frame(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1"))
r <- rle(as.character(df$var1))
r$values <- seq_along(r$values)
df$var2 <- inverse.rle(r)
Run Code Online (Sandbox Code Playgroud)

简洁版本:

df$var2 <- with(rle(as.character(df$var1)), rep(seq_along(values), lengths))
Run Code Online (Sandbox Code Playgroud)

这是一个解决方案data.table

library("data.table")
dt <- data.table(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1"))
dt[, var2:=rleid(var1)]
Run Code Online (Sandbox Code Playgroud)