【问题标题】:How to add a column that counts duplicates in sequence?如何添加按顺序计算重复项的列?
【发布时间】:2016-03-14 00:02:43
【问题描述】:

我希望在数据框 (integrates2) 中添加一列,以按顺序计算重复项。下面是数据的样子:

name    program  date of contact   helper column
John     ffp        10/11/2014          2
John     TP         10/27/2014          2
Carlos   TP         11/19/2015          3
Carlos   ffp        12/1/2015           3
Carlos   wfd        12/31/2015          3
Jen      ffp        9/9/2014            2
Jen      TP         9/30/2014           2    

这是在特定日期参加了特定计划的人员列表。我添加了一个帮助列来计算重复次数并对联系日期进行排序。我正在计算现有程序的组合(例如 ffp-tp、tp-ffp-wfd)。

为了做到这一点,我想实现以下代码,以便在名为“program2”的新列的帮助下转置有序组合:

 #transpose the programs 
 require(reshape2) dcast(integrates2, name ~ program2, value.var=”program”)

然后我打算用下面的代码把结果转成表格和数据框并统计频率:

 res = table(integrates2)
 resdf = as.data.frame(res)

我在以下链接中看到了这个: Count number of time combination of events appear in dataframe columns ext

我需要的“program2”是这样的:

  Name    program  date of contact   helper column   program2
  John     ffp        10/11/2014          2             1
  John     TP         10/27/2014          2             2
  Carlos   TP         11/19/2015          3             1
  Carlos   ffp        12/1/2015           3             2
  Carlos   wfd        12/31/2015          3             3

这样,我可以使用“program2”转置到不同的列,然后计算组合。最终结果应如下所示:

    program  pro1   pro2   freq      
     ffp     tp             2   
     TP      ffp    wfd     1    

我确信有更简单的方法可以做到这一点,但随着我的学习,这就是我所在的地方。感谢大家的帮助!

【问题讨论】:

    标签: r


    【解决方案1】:

    在考虑了这个问题之后,我认为以下是要走的路。如果您不介意组合所有程序名称,您可以执行以下操作。这可能要好得多。

    setDT(mydf)[, list(type = paste(program, collapse = "-")), by = name][,
               list(total = .N), by = type]
    
    #         type total
    #1:     ffp-TP     2
    #2: TP-ffp-wfd     1
    

    如果您想分隔程序名称,可以使用 splitstackshape 包中的 cSplit() 来实现。

    setDT(mydf)[, list(type = paste(program, collapse = "-")), by = name][,
                  list(total = .N), by = type] -> temp
    
    cSplit(temp, splitCols = "type", sep = "-")
    
    #   total type_1 type_2 type_3
    #1:     2    ffp     TP     NA
    #2:     1     TP    ffp    wfd
    

    dplyr代码的等价是:

    group_by(mydf, name) %>%
    summarise(type = paste(program, collapse = "-")) %>%
    count(type)
    
    #        type     n
    #       (chr) (int)
    #1     ffp-TP     2
    #2 TP-ffp-wfd     1
    

    数据

    mydf <- structure(list(name = c("John", "John", "Carlos", "Carlos", "Carlos", 
    "Jen", "Jen"), program = c("ffp", "TP", "TP", "ffp", "wfd", "ffp", 
    "TP"), dateOfContact = c("10/11/2014", "10/27/2014", "11/19/2015", 
    "12/1/2015", "12/31/2015", "9/9/2014", "9/30/2014"), helperColumn = c(2L, 
    2L, 3L, 3L, 3L, 2L, 2L)), .Names = c("name", "program", "dateOfContact", 
    "helperColumn"), class = "data.frame", row.names = c(NA, -7L))
    

    【讨论】:

    • 爵士乐,谢谢!我在您编写代码时使用了 setDT 函数,它运行良好。我也要测试 dplyr 代码。
    • @LoF10 很高兴为您提供帮助。 :)
    • 快速问题,假设我想保留名称或 id 变量,以便稍后我可以将其与另一个数据集合并,我如何更改代码以保留名称?我尝试了以下方法,但没有成功: setDT(mydf)[, list(type = paste(name, program, collapse = "-")), by = name][, list(total = .N), by =类型]。我认为“粘贴”可以让我添加另一个向量“名称”。有任何想法吗?谢谢!
    • @LoF10 最终结果显示节目模式的频率。所以你有ffp-TP 类型下的 John 和 Jen。如果您想为名称添加一列,您希望如何?
    • @LoF10 你在寻找这样的东西吗? setDT(mydf)[, list(type = paste(program, collapse = "-")), by = name][, list(total = .N, name = paste(name, collapse = ",")), by = type].
    【解决方案2】:

    编辑:返回排列

    dplyr

    library(dplyr)
    integrates2 %>% group_by(name) %>% summarise(prg1 = program[1],
                                                 prg2 = program[2],
                                                 prg3 = program[3]) %>% 
      select(prg1, prg2, prg3) %>% group_by(prg1, prg2, prg3) %>% summarise(freq = n())
    

    返回

    Source: local data frame [2 x 4]
    Groups: prg1, prg2 [?]
    
        prg1   prg2   prg3  freq
      (fctr) (fctr) (fctr) (int)
    1    ffp     TP     NA     2
    2     TP    ffp    wfd     1
    

    使用来自 cmets 的 mydf2,它会产生

    Source: local data frame [3 x 4]
    Groups: prg1, prg2 [?]
    
       prg1  prg2  prg3  freq
      (chr) (chr) (chr) (int)
    1   ffp    TP    NA     1
    2    TP   ffp    NA     1
    3   wfd    TP   ffp     1
    

    链条

    • name 上调用group_by 以分隔案例;
    • summariseprogram 转置为三列;
    • select 缩小到这些列;
    • group_by所有prg*列所以
    • summarise 可以将它们分成不同的组,并添加 freq 这些组的出现次数。

    或者,如果你愿意,你可以在基础 R 中完成所有事情,尽管它的可读性要差得多(至少使用这种特殊方法):

    tab <- table(sapply(split(integrages2$program, integrates2$name), 
                 function(x){paste(x, collapse = '-')}))
    prgs <- strsplit(names(tab), '-')
    programs <- do.call(rbind, lapply(prgs, function(x){
      c(x, rep(NA, max(sapply(prgs, length)-length(x))))
      }))
    programs <- cbind(as.data.frame(programs), matrix(tab))
    names(programs) <- c(paste0('prgm', seq(length(programs)-1)), 'freq')
    

    一个非常快速和肮脏的版本,它将系列折叠成字符串:

    table(sapply(split(integrates2$program, integrates2$name), 
                 function(x){paste(x, collapse = '-')}))
    

    返回

    ffp-TP TP-ffp-wfd 
         2          1 
    

    或者如果包裹在as.matrix中,

               [,1]
    ffp-TP        2
    TP-ffp-wfd    1
    

    预编辑版本:返回组合

    使用reshape2,您可以使用dcast制作程序组合的data.frame(用[,-1]去掉我们不关心的names):

    library(reshape2)
    programs <- dcast(integrates2, name ~ program, value.var = 'program')[,-1]
    

    programs 看起来像:

    > programs
      ffp TP  wfd
    1 ffp TP  wfd
    2 ffp TP <NA>
    3 ffp TP <NA>
    

    您现在可以使用dplyrprograms 的所有列名进行分组(在此处以编程方式完成,但如果您想查看发生了什么,您可以使用group_by(ffp, TP, wfd) 手动完成)和summarise ,使用n() 获取组中的行数:

    library(dplyr)
    programs %>% group_by_(.dots = names(programs)) %>% summarise(freq = n())
    

    返回

    Source: local data frame [2 x 4]
    Groups: ffp, TP [?]
    
        ffp    TP   wfd  freq
      (chr) (chr) (chr) (int)
    1   ffp    TP   wfd     1
    2   ffp    TP    NA     2
    

    【讨论】:

    • 我在玩原始数据。我使用以下修改后的数据,但您的代码没有得到预期的结果。我错过了什么吗? mydf2 &lt;- structure(list(name = c("John", "John", "Carlos", "Carlos", "Carlos", "Jen", "Jen"), program = c("TP", "ffp", "wfd", "TP", "ffp", "ffp", "TP"), dateOfContact = c("10/11/2014", "10/27/2014", "11/19/2015", "12/1/2015", "12/31/2015", "9/9/2014", "9/30/2014"), helperColumn = c(2L, 2L, 3L, 3L, 3L, 2L, 2L)), .Names = c("name", "program", "dateOfContact", "helperColumn"), class = "data.frame", row.names = c(NA, -7L))
    • @jazzurro 它对我来说很好用,如果你把mydf2 放在integrates2 的行中,使programs (原始data.frame 的名称,根据OP) .
    • 你到底看到了三种不同的程序模式吗?我遵循了您的代码,尽管应该有三种模式,但我最终只看到了两种模式; mydf2 具有三种不同的程序模式。
    • 哦,我明白了,我以不同的方式阅读了这个问题。我把它当作组合,而不是排列,因为顺序与组合无关。重读,不清楚是什么意思...@LoF10 你能澄清一下吗?
    • “转置有序组合”,绝对是在寻找顺序重要的排列。这就是为什么我最初按姓名排序,然后按联系日期*with(integrates2,安排(姓名,联系日期)。我试图查看哪些程序路径最常见,然后将它们与结果联系起来。所以在这个特别数据框只有两个程序路径:“ffp-tp”和“tp-ffp-wfd”。
    猜你喜欢
    • 2015-03-09
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 2015-01-12
    • 2010-11-08
    • 2022-11-04
    • 2022-06-14
    相关资源
    最近更新 更多