假设我有以下数据框
set.seed(123)
df <- data.frame(var1=(runif(10)>0.5)*1)
var1
可以有任何类型/数量的级别,而不是特定的0和1s
我想创建一个var2
,每当var1
使用for 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
数据框的另一个选项可能是:
df <- data.frame(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1"))
在这种情况下,结果应为:
var1 var2
a 1
a 1
1 2
0 3
b 4
b 4
b 4
c 5
1 6
1 6
答案 0 :(得分:10)
以弗里克先生回答:
df$var2 <- cumsum(c(0,as.numeric(diff(df$var1))!=0))
但如果你不想使用diff
,你仍然可以使用:
df$var2 <- c(0,cumsum(as.numeric(with(df,var1[1:(length(var1)-1)] != var1[2:length(var1)]))))
它从0开始,而不是1,但我确定你知道如果你想改变它。
答案 1 :(得分:9)
如何使用diff()
和cumsum()
。例如
df$var2 <- cumsum(c(1,diff(df$var1)!=0))
答案 2 :(得分:8)
这些看起来像一个游程编码(rle)
x = c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1")
r = rle(x)
与
> 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"
这表示第一个值(&#34; a&#34;)连续出现2次,然后&#34; 1&#34;发生过一次,等等。你所追求的是沿着长度创建一个序列,并按照元素出现的次数复制序列的每个元素,所以
> rep(seq_along(r$lengths), r$lengths)
[1] 1 1 2 3 4 4 4 5 6 6
其他答案是半欺骗性的,因为它们依赖于列是因子();当列实际上是一个字符()时,它们会失败。
> diff(x)
Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] :
non-numeric argument to binary operator
解决方法是将字符映射到整数,沿着
行> diff(match(x, x))
[1] 0 2 1 1 0 0 3 -5 0
嗯,但是我说过,我发现那些不会影响因素!
> 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"
答案 3 :(得分:4)
以下是使用inverse.rle()
的基础R的另一种解决方案:
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)
简短版本:
df$var2 <- with(rle(as.character(df$var1)), rep(seq_along(values), lengths))
以下是data.table
的解决方案:
library("data.table")
dt <- data.table(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1"))
dt[, var2:=rleid(var1)]
答案 4 :(得分:2)
我只复制上面的Martin Morgan的rle()
答案,但是使用tidyverse约定来实现它,以便将分组列直接添加到数据帧/小标题中,这是我大多数时候最终使用的方式。
## 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