【问题标题】:Calculating a function of contiguous states with dplyr without using group_by?在不使用 group_by 的情况下使用 dplyr 计算连续状态的函数?
【发布时间】:2016-01-06 21:50:01
【问题描述】:

我有一个如下所示的数据框:

States <- data.frame(State = c('a','a','b','c','c','a','b'),Duration = c(2,3,5,4,7,2,1))

我想找出这个系统每次访问一个州所花费的持续时间。也就是说,我想要

State  Duration
a       5
b       5
c      11
a       2
b       1

快速回答使用group_by,但是错了;

States %>% group_by(State) %>% summarise(Total = sum(Duration))

给予

   State Total
  (fctr) (dbl)
1      a     7
2      b     6
3      c    11

你会怎么做?

谢谢,

比尔

这是一个更简单的版本,可能更接近我的问题的本质。

States <- data.frame(State = c('a','a','a','b','c','c','b','a','b','d'),Duration = c(0,2,2,3,0,5,4,7,2,1))

     States
   State Duration
1      a        0
2      a        2
3      a        2
4      b        3
5      c        0
6      c        5
7      b        4
8      a        7
9      b        2
10     d        1

我确实想总结一下连续访问各州所花费的时间。对于这种情况,那就是

a 2
b 3
c 5
b 4
a 7
b 2
d 1

换句话说,您为每次国事访问取最后一个持续时间,如果该访问有多个条目,则第一个持续时间为 0(我没有设计数据;我只是在处理它) .

如果我像上面那样使用 group_by,dplyr 会按状态处理数据框,这给了我错误的答案:每个状态一个条目,而不是每次访问一个条目。

这有帮助吗?我认为它们都是相关的:有没有一种方法可以聚合行而不重新排列它们?

【问题讨论】:

  • @DatamineR 啊 - 我读到第二个代码块是想要的结果,第三个代码块是他尝试过的,第四个代码块是他错误尝试的输出。
  • 为了澄清,第一个代码块创建输入数据。第二个显示我想要什么。第三个显示使用 group_by 的错误代码,第四个显示错误代码的结果。我正在寻找产生第二个代码块的代码。 @tospig,你是对的。

标签: r dplyr


【解决方案1】:

您可以使用运行长度编码创建新的分组变量。我确信有一种更 dplyr-ish 的方式来执行其中的一些步骤。

rles <- rle(as.character(States$State))
States$new.groups <- rep(LETTERS[seq_along(rles[[1]])], rles$lengths)

durations <- States %>% group_by(new.groups) %>%
               summarise(Total = sum(Duration)) %>% 
               transform(States = new.groups, new.groups = NULL)

durations$State <- rles$values # assign the appropriate values to duration$State

#Source: local data frame [5 x 2]
#
#   State Total
#   (chr) (dbl)
#1      a     5
#2      b     5
#3      c    11
#4      a     2
#5      b     1

如果您可以合并 data.table 函数,您可以使用非常漂亮的 rleid 来获得看起来更简洁的代码:

library(data.table)
States$new.groups <- rleid(States$State)

    durations <- States %>% group_by(new.groups) %>%
               summarise(Total = sum(Duration)) %>% 
               transform(States = new.groups, new.groups = NULL)

durations$States <- rle(as.character(States$State))$values  # still had to use regular rle here

【讨论】:

  • rle,一个非常有趣的功能,我不知道。
  • @PereG 这是一个很棒的功能。实际上,data.tablerleid 函数实际上可能更适合这项任务!
  • 谢谢!两种解决方案似乎都朝着有用的方向发展,但到目前为止我最喜欢 rleid() 建议。我一直在寻找 dplyr-ish 解决方案,但不知道 rle() 或 rleid()。
【解决方案2】:

计算一个虚拟变量

for (i in 1:(dim(States)[1]-1)){
      States$new[1] <- "A"
      States$new[i+1] <- ifelse(States$State[i] == States$State[i+1], 
            States$new[i], 
            LETTERS[i]
      )      
}

构建新的 data.frame 并格式化

data <- data.frame(cbind(as.character(unique(States$State)), rowsum(States$Duration, States$new)))
names(data) <- c("State", "Duration")
rownames(data) <- NULL
data

这不是一个优雅的代码,但使用您的数据,它可以工作。


编辑后实现建议的解决方案:

States2 <- States[States$Duration != 0,]

现在,同样的 for 循环

for (i in 1:(dim(States2)[1]-1)){
      States2$new[1] <- "A"
      States2$new[i+1] <- ifelse(States2$State[i] == States2$State[i+1], 
                                States2$new[i], 
                                LETTERS[i]
      )      
}

还有一段新代码:

library(data.table)
States2 <- as.data.table(States2)
# set "new" as the key variable
setkey(States2, new)     
# select the last row of new
States3 <- as.data.table(States2[unique(States2$new), mult = "last"])
# clean the data
States3[, new := NULL]
States3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-27
    • 2015-03-25
    • 1970-01-01
    • 2021-04-10
    • 1970-01-01
    • 2017-07-12
    相关资源
    最近更新 更多