【问题标题】:Sum over rows with multiple changing conditions R data.table对具有多个变化条件的行求和 R data.table
【发布时间】:2014-09-30 02:49:01
【问题描述】:

我正在尝试在 data.frame 或 data.table 中创建一个具有两个条件的列。我看到的帖子和我在下面尝试修改的帖子的不同之处在于我没有条件的“价值”,但条件取决于data.frame 中的其他变量。

假设这是我的数据框:

mydf <- data.frame (Year = c(2000, 2001, 2002, 2004, 2005,
                             2007, 2000, 2001, 2002, 2003,
                             2003, 2004, 2005, 2006, 2006, 2007),
                    Name = c("Tom", "Tom", "Tom", "Fred", "Gill",
                             "Fred", "Gill", "Gill", "Tom", "Tom",
                             "Fred", "Fred", "Gill", "Fred", "Gill", "Gill"))

我想知道这 3 位受试者在过去 5 年内经历了多少次事件。但是,如果事件日期可以追溯到 5 年以上,我不想包括它。我想我可以做一个指标变量的总和(如果受试者在当年经历了事件,则设置为 1),同时指定一些类似于Year &lt; Year &amp; Year &gt;= Year-5 的内容。所以基本上总结了小于焦点年和大于等于焦点年前5年的经验。

我已经创建了一个求和指标和一个焦点年的变量 - 5

mydf$Ind <- 1
mydf$Yearm5 <- mydf$Year-5

然后我转换为速度数据表(原始df有+60k obs)

library(data.table)
mydf <- data.table(mydf)

现在的问题是我无法让这两个条件起作用。我所看到的帖子似乎都知道一个特定的值作为子集(例如R data.table subsetting on multiple conditions.),但在我的情况下,值从观察变为观察(不确定这是否意味着我需要做一些循环?)。

我认为我需要一些类似的东西:

mydf[, c("Exp"):= sum(Ind), by = c("Name")][Year < Year & Year >= Yearm5]

给予:

Empty data.table (0 rows) of 5 cols: Year,Name,Ind,Yearm5,Exp

只使用一个条件

mydf1 <- mydf[, c("Exp"):= sum(Ind), by = c("Name")][Year >= Yearm5] 

提供了完整的体验,所以我假设 Year &lt; Year 条件有问题。

我不太确定是什么。我还尝试修改以下建议: how to cumulatively add values in one vector in R 再次运气不佳,我指定条件的方式似乎有问题。

library(dplyr)
mytest1 <- mydf %>%
           group_by(Name, Year) %>%
           filter(Year < Year & Year >= Yearm5) %>%
           mutate(Exp = sum(Ind))

结果应如下所示:

myresult <- data.frame (Year = c(2003, 2004, 2004, 2006,
                                 2007, 2000, 2001, 2005,
                                 2005, 2006, 2007, 2000,
                                 2001, 2002, 2002, 2003),
                        Name = c("Fred", "Fred", "Fred", "Fred",
                                 "Fred", "Gill", "Gill", "Gill",
                                 "Gill", "Gill", "Gill", "Tom",
                                 "Tom", "Tom", "Tom", "Tom"),
                        Ind = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
                        Exp = c(0, 1, 1, 3, 4, 0, 1, 1, 1, 2, 3, 0, 1, 2, 2, 4),
                        Yearm5 = c(1998, 1999, 1999, 2001, 2002,
                                   1995, 1996, 2000, 2000, 2001,
                                   2002, 1995, 1996, 1996, 1997, 1998))

任何帮助或指点将不胜感激!

【问题讨论】:

    标签: r sum data.table multiple-conditions


    【解决方案1】:

    这是一个更多的data.table 方法,使用roll。

    setDT(mydf)
    
    # this is our desired end point
    boundary = mydf[, list(Name, year.end = Year + 4)]
    
    # set the key for the following merges
    setkey(mydf, Name, Year)
    setkey(boundary, Name, year.end)
    
    # add indices that will keep track of the positions to compute deltas
    mydf[, idx := .I]
    boundary[, idx := .I]
    
    # merge, rolling to match the end correctly, and then subtract the indices
    # to get the desired delta.
    # Note that we need to unique data because of duplicates.
    # Depending on data you may also need to add `allow.cartesian = TRUE`.
    # Final note - in data.table <= 1.9.2 you should omit the `by = .EACHI` part.
    
    mydf[unique(boundary)[unique(mydf), list(Exp = i.idx - idx),
                          roll = -Inf, by = .EACHI]]
    #    Year Name idx Exp
    # 1: 2003 Fred   1   0
    # 2: 2004 Fred   2   1
    # 3: 2004 Fred   3   1
    # 4: 2006 Fred   4   3
    # 5: 2007 Fred   5   4
    # 6: 2000 Gill   6   0
    # 7: 2001 Gill   7   1
    # 8: 2005 Gill   8   1
    # 9: 2005 Gill   9   1
    #10: 2006 Gill  10   2
    #11: 2007 Gill  11   3
    #12: 2000  Tom  12   0
    #13: 2001  Tom  13   1
    #14: 2002  Tom  14   2
    #15: 2002  Tom  15   2
    #16: 2003  Tom  16   4
    

    【讨论】:

    • 太棒了。我以为有办法使用roll,虽然我找不到。
    • 非常感谢这种方法,也可以完美地处理我的数据。我不太确定我是否了解roll 的工作原理,也找不到相关文档。本着学习的精神,是否有可能获得一些文档的链接,以便我将来应用它?
    • 抱歉,我在第 5 页底部的cran.r-project.org/web/packages/data.table/data.table.pdf 上找到了它。
    【解决方案2】:

    这是一种使用rollapply 和data.table 的方法

    library(zoo)
     setDT(mydf)
     setkey(mydf, Name,Year)
     # create a data.table that has all Years and incidences including the 5 year window 
     # and sum up the number of incidences per year for each subject 
    m <- mydf[CJ(unique(Name),seq(min(Year)-5, max(Year))),allow.cartesian=TRUE][,
                list(Ind = unique(Ind), I2 = sum(Ind,na.rm=TRUE)),
                keyby=list(Name,Year)]
    # use rollapply over this larger data.table to get the number of
    # incidences in the previous 5 years (not including this year (hence head(x,-1))
    m[,Exp := rollapply(I2, 5, function(x) sum(head(x,-1)), 
                        align = 'right', fill=0),by=Name]
    # join with the original to create your required data
    m[mydf, !'I2']
       Name Year Ind Exp
    #  1: Fred 2003   1   0
    #  2: Fred 2004   1   1
    #  3: Fred 2004   1   1
    #  4: Fred 2006   1   3
    #  5: Fred 2007   1   4
    #  6: Gill 2000   1   0
    #  7: Gill 2001   1   1
    #  8: Gill 2005   1   1
    #  9: Gill 2005   1   1
    # 10: Gill 2006   1   2
    # 11: Gill 2007   1   3
    # 12:  Tom 2000   1   0
    # 13:  Tom 2001   1   1
    # 14:  Tom 2002   1   2
    # 15:  Tom 2002   1   2
    # 16:  Tom 2003   1   4
    

    【讨论】:

    • 非常感谢,它很有魅力,而且速度也很快。我不会自己想出这个主意。我想只是为了澄清其他用户require(zoo) 需要在运行代码之前调用。
    • @Rkook -- 确实并且已修复。 \
    【解决方案3】:

    使用data.table,我认为您要查找的语法应该是这样的:

    setDT(mydf)
    mydf[ , Exp := rank(x=Year,ties.method="min")-1, by=Name]
    

    【讨论】:

    • 非常感谢您的快速回复和建议。我以前没有使用过排名函数。但是,它没有给出想要的结果(我使用cumsum 得到了相同的结果)。请注意,“Gill”在 2006 年和 2007 年的 Exp 值应分别为 3 和 4,因为 2000 年和 2001 年比 2006 年和 2007 年早 5 年以上,因此不应将经验包括在总和中。看看mydf &lt;- mydf[with(mydf, order(Name,Year)),] 就更清楚了。
    • @Mike.Gahan:我上面的评论不正确,Exp 的值在 2006 年和 2007 年应该分别是 2 和 3,即使是基本的数学似乎也不再适用了 :(.跨度>
    猜你喜欢
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 1970-01-01
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多