按连接值对R数据帧进行分组

时间:2016-09-15 12:56:42

标签: r dataframe group-by run-length-encoding

我在R中找不到这个常见分组问题的解决方案:

这是我的原始数据集

ID  State
1   A
2   A
3   B
4   B
5   B
6   A
7   A
8   A
9   C
10  C

这应该是我的分组结果数据集

State   min(ID) max(ID)
A       1       2
B       3       5
A       6       8
C       9       10

因此,我们的想法是首先按ID列(或时间戳列)对数据集进行排序。然后,应将没有间隙的所有连接状态组合在一起,并返回最小和最大ID值。它与rle方法有关,但这不允许计算组的最小值,最大值。

有什么想法吗?

4 个答案:

答案 0 :(得分:6)

你可以尝试:

library(dplyr)
df %>%
  mutate(rleid = cumsum(State != lag(State, default = ""))) %>%
  group_by(rleid) %>%
  summarise(State = first(State), min = min(ID), max = max(ID)) %>%
  select(-rleid)

或者正如@alistaire在评论中提到的那样,你可以在group_by()内使用相同的语法进行变异,结合前两个步骤。窃取data.table::rleid()并使用summarise_all()简化:

df %>% 
  group_by(State, rleid = data.table::rleid(State)) %>% 
  summarise_all(funs(min, max)) %>% 
  select(-rleid)

给出了:

## A tibble: 4 × 3
#   State   min   max
#  <fctr> <int> <int>
#1      A     1     2
#2      B     3     5
#3      A     6     8
#4      C     9    10

答案 1 :(得分:5)

这是一种方法,它使用基数R中的rle函数为您提供的数据集。

# get the run length encoding
temp <- rle(df$State)

# construct the data.frame
newDF <- data.frame(State=temp$values,
                    min.ID=c(1, head(cumsum(temp$lengths) + 1, -1)),
                    max.ID=cumsum(temp$lengths))

返回

newDF
  State min.ID max.ID
1     A      1      2
2     B      3      5
3     A      6      8
4     C      9     10

请注意rle需要一个字符向量而不是一个因子,所以我使用下面的as.is参数。

正如@ cryo111在下面的注释中所述,数据集可能是无序的时间戳,与rle中计算的长度不对应。要使此方法起作用,您需要先将时间戳转换为日期时间格式,使用as.POSIXct之类的函数,使用df <- df[order(df$ID),],然后对上述方法稍作修改:< / p>

# get the run length encoding
temp <- rle(df$State)

# construct the data.frame
newDF <- data.frame(State=temp$values,
                    min.ID=df$ID[c(1, head(cumsum(temp$lengths) + 1, -1))],
                    max.ID=df$ID[cumsum(temp$lengths)])

数据

df <- read.table(header=TRUE, as.is=TRUE, text="ID  State
1   A
2   A
3   B
4   B
5   B
6   A
7   A
8   A
9   C
10  C")

答案 2 :(得分:4)

data.table的想法:

require(data.table)

dt <- fread("ID  State
1   A
            2   A
            3   B
            4   B
            5   B
            6   A
            7   A
            8   A
            9   C
            10  C")

dt[,rle := rleid(State)]
dt2<-dt[,list(min=min(ID),max=max(ID)),by=c("rle","State")]

给出:

   rle State min max
1:   1     A   1   2
2:   2     B   3   5
3:   3     A   6   8
4:   4     C   9  10

我们的想法是识别带有rleid的序列,然后通过元组minmax获取ID的{​​{1}}和rle

你可以用

删除rle列
State

链式:

dt2[,rle:=NULL]

您可以直接在 dt2<-dt[,list(min=min(ID),max=max(ID)),by=c("rle","State")][,rle:=NULL] 内使用rleid来缩短上述代码:

by

答案 3 :(得分:2)

以下是使用基础R中的<div ng-app="myApp" ng-controller="myCtrl" class="container"> <div class="col-sm-10 center-block text-center"> <input type="text" class="form-control" placeholder="Type to search..." ng-model="word" /> <div ng-repeat="letter in word.split('') track by $index"> <span> {{letter }} </span> </div> </div> </div> rle的另一种尝试:

aggregate

数据

rl <- rle(df$State)
newdf <- data.frame(ID=df$ID, State=rep(1:length(rl$lengths),rl$lengths))
newdf <- aggregate(ID~State, newdf, FUN = function(x) c(minID=min(x), maxID=max(x)))
newdf$State <- rl$values

  # State ID.minID ID.maxID
# 1     A        1        2
# 2     B        3        5
# 3     A        6        8
# 4     C        9       10