R中唯一值的累积计数

use*_*405 14 r unique cumulative-sum

我的数据集的简化版本如下所示:

depth value
   1     a
   1     b
   2     a
   2     b
   2     b
   3     c
Run Code Online (Sandbox Code Playgroud)

我想创建一个新的数据集,对于每个"深度"值,我将从顶部开始具有唯一值的累积数量.例如

depth cumsum
 1      2
 2      2
 3      3
Run Code Online (Sandbox Code Playgroud)

关于如何做到这一点的任何想法?我对R比较新.

Aru*_*run 13

我发现这是一个使用factor和设置levels仔细的完美案例.我会data.table在这里使用这个想法.确保您的value专栏character(不是绝对要求).

  • 第1步:通过只获取行data.frame来转换为.data.tableunique

    require(data.table)
    dt <- as.data.table(unique(df))
    setkey(dt, "depth") # just to be sure before factoring "value"
    
    Run Code Online (Sandbox Code Playgroud)
  • 第2步:转换value为a factor并强制转换为numeric.确保自己设置级别(这很重要).

    dt[, id := as.numeric(factor(value, levels = unique(value)))]
    
    Run Code Online (Sandbox Code Playgroud)
  • 步骤3:将键列设置depth为子集,然后选择最后一个值

     setkey(dt, "depth", "id")
     dt.out <- dt[J(unique(depth)), mult="last"][, value := NULL]
    
    #    depth id
    # 1:     1  2
    # 2:     2  2
    # 3:     3  3
    
    Run Code Online (Sandbox Code Playgroud)
  • 步骤4:由于深度增加的行中的所有值都应至少具有前一行的值,因此您应该使用它cummax来获取最终输出.

    dt.out[, id := cummax(id)]
    
    Run Code Online (Sandbox Code Playgroud)

编辑:以上代码仅供参考.实际上,您根本不需要第3列.这就是我写最终代码的方式.

require(data.table)
dt <- as.data.table(unique(df))
setkey(dt, "depth")
dt[, value := as.numeric(factor(value, levels = unique(value)))]
setkey(dt, "depth", "value")
dt.out <- dt[J(unique(depth)), mult="last"]
dt.out[, value := cummax(value)]
Run Code Online (Sandbox Code Playgroud)

这是一个更棘手的例子和代码的输出:

df <- structure(list(depth = c(1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6), 
                value = structure(c(1L, 2L, 3L, 4L, 1L, 3L, 4L, 5L, 6L, 1L, 1L), 
                .Label = c("a", "b", "c", "d", "f", "g"), class = "factor")), 
                .Names = c("depth", "value"), row.names = c(NA, -11L), 
                class = "data.frame")
#    depth value
# 1:     1     2
# 2:     2     4
# 3:     3     4
# 4:     4     5
# 5:     5     6
# 6:     6     6
Run Code Online (Sandbox Code Playgroud)

  • 这是一个'dplyr`版本:`df%>%arrange(depth)%>%mutate(value = cummax(as.numeric(factor(value,levels = unique(value)))))%>%arrange(depth, desc(value))%>%distinct(depth)`. (4认同)

jub*_*uba 7

这是另一种尝试:

numvals <- cummax(as.numeric(factor(mydf$value)))
aggregate(numvals, list(depth=mydf$depth), max)
Run Code Online (Sandbox Code Playgroud)

这使:

  depth x
1     1 2
2     2 2
3     3 3
Run Code Online (Sandbox Code Playgroud)

它似乎也适用于@ Arun的例子:

  depth x
1     1 2
2     2 4
3     3 4
4     4 5
5     5 6
6     6 6
Run Code Online (Sandbox Code Playgroud)


New*_*ias 7

dplyr 尝试。

df %>%
  #group_by(group)%>% if you have a third variable and you want to achieve the same results for each group
  mutate(cum_unique_entries = cumsum(!duplicated(value))) %>%
  group_by(depth) %>% # add group variable for more layers
  summarise(cum_unique_entries = last(cum_unique_entries))
Run Code Online (Sandbox Code Playgroud)


Dav*_*son 5

一个好的第一步是创建一个TRUEor列FALSE,它TRUE用于每个值的第一个以及该值FALSE的后续出现。这可以使用duplicated以下方法轻松完成:

mydata$first.appearance = !duplicated(mydata$value)
Run Code Online (Sandbox Code Playgroud)

最好使用aggregate. 在这种情况下,它表示对 的first.appearance每个子集中的列求和depth

newdata = aggregate(first.appearance ~ depth, data=mydata, FUN=sum)
Run Code Online (Sandbox Code Playgroud)

结果将如下所示:

  depth first.appearance
1     1  2
2     2  0
3     3  1
Run Code Online (Sandbox Code Playgroud)

不过,这仍然不是累积总和。为此,您可以使用该cumsum函数(然后删除旧列):

newdata$cumsum = cumsum(newdata$first.appearance)
newdata$first.appearance = NULL
Run Code Online (Sandbox Code Playgroud)

所以回顾一下:

mydata$first.appearance = !duplicated(mydata$value)
newdata = aggregate(first.appearance ~ depth, data=mydata, FUN=sum)
newdata$cumsum = cumsum(newdata$first.appearance)
newdata$first.appearance = NULL
Run Code Online (Sandbox Code Playgroud)

输出:

  depth cumsum
1     1      2
2     2      2
3     3      3
Run Code Online (Sandbox Code Playgroud)


G. *_*eck 5

这可以通过使用sqldf包的单个 SQL 语句以相对干净的方式编写。假设DF是原始数据框:

library(sqldf)

sqldf("select b.depth, count(distinct a.value) as cumsum
    from DF a join DF b 
    on a.depth <= b.depth
    group by b.depth"
)
Run Code Online (Sandbox Code Playgroud)