【问题标题】:R: Avoid loop or row apply functionR:避免循环或行应用功能
【发布时间】:2015-08-22 15:23:16
【问题描述】:

我关注了两个数据框 df_salesdf_supply

我想以这样一种方式将销售与供应合并,以使我的 df_sales 表在以下条件下具有来自 df_supply 的 DATE_SUPPLY 和 QNT_SUPPLY

*条件:DATE_SUPPLY应该是对应“STORE”对应“ITEM”的最近DATE_SUPPLY,即DATE_SALE <- max(df_supply[df_supply$DATE_SUPPLY <= df_sales$DATE_SALE & df_supply$STORE == df_sales$STORE & df_supply$ITEM == df_sales$ITEM,]$DATE_SUPPLY)*

可以使用行应用函数或简单地编写循环。但我有巨大的数据集,所以不想循环。

df_sales <- data.frame("STORE"=c(1001,1001,1001,1001,1001,1002,1002,1002,1002,1002),"ITEM"=c(13048, 13057, 13082, 13048, 13057, 13145, 13166, 13229, 13057, 13048),"DATE_SALE"=as.Date(c("1/1/2014","1/1/2014","1/2/2014","1/2/2014","1/2/2014","1/2/2014","1/3/2014","1/3/2014","1/3/2014","1/4/2014"),"%m/%d/%Y"),"QNT_SALE"=c(1,1,1,1,1,1,1,1,1,1))

df_sales

   STORE  ITEM  DATE_SALE QNT_SALE
1   1001 13048 2014-01-01        1
2   1001 13057 2014-01-01        1
3   1001 13082 2014-01-02        1
4   1001 13048 2014-01-02        1
5   1001 13057 2014-01-02        1
6   1002 13145 2014-01-02        1
7   1002 13166 2014-01-03        1
8   1002 13229 2014-01-03        1
9   1002 13057 2014-01-03        1
10  1002 13048 2014-01-04        1

df_supply <- data.frame("STORE"=c(1001,1002,1001,1001,1002,1002,1002,1002,1002,1002),"ITEM"=c(13048,13229,13057,13082,13145,13166,13229,13057,13048,13048),"DATE_SUPPLY"=as.Date(c("1/31/2013","1/31/2013","1/31/2013","1/1/2014","1/2/2014","1/2/2014","1/2/2014","1/2/2014","1/3/2014","2/1/2014"),"%m/%d/%Y"),"QNT_SUPPLY"=c(2,1,2,1,1,1,2,3,1,2))
df_supply
   STORE  ITEM DATE_SUPPLY CUM_QNT_SUPPLY
1   1001 13048 2013-01-31          2
2   1002 13229 2013-01-31          1
3   1001 13057 2013-01-31          2
4   1001 13082 2014-01-01          1
5   1002 13145 2014-01-02          1
6   1002 13166 2014-01-02          1
7   1002 13229 2014-01-02          2
8   1002 13057 2014-01-02          3
9   1002 13048 2014-01-03          1
10  1002 13048 2014-02-01          2



Output Required:
Sales Vs Supply
   STORE  ITEM  DATE_SALE QNT_SALE  DATE_SUPPLY QNT_SUPPLY
1   1001 13048 2014-01-01        1  2013-01-31          2
2   1001 13057 2014-01-01        1  2013-01-31          2
3   1001 13082 2014-01-02        1  2014-01-01          1
4   1001 13048 2014-01-02        1  2013-01-31          2
5   1001 13057 2014-01-02        1  2013-01-31          2
6   1002 13145 2014-01-03        1  2014-01-02          1
7   1002 13166 2014-01-03        1  2014-01-02          1
8   1002 13229 2014-01-03        1  2014-01-02          2
9   1002 13057 2014-01-03        1  2014-01-02          3
10  1002 13048 2014-01-04        1  2014-01-03          1

【问题讨论】:

    标签: r merge dataframe data.table


    【解决方案1】:

    使用来自data.table滚动连接

    require(data.table)
    setkey(setDT(df_supply), STORE, ITEM, DATE_SUPPLY)
    idx = df_supply[df_sales, roll=Inf, which=TRUE]
    cbind(df_sales, df_supply[idx, 3:4])
    #    STORE  ITEM  DATE_SALE QNT_SALE DATE_SUPPLY QNT_SUPPLY
    # 1   1001 13048 2014-01-01        1  2013-01-31          2
    # 2   1001 13057 2014-01-01        1  2013-01-31          2
    # 3   1001 13082 2014-01-02        1  2014-01-01          1
    # 4   1001 13048 2014-01-02        1  2013-01-31          2
    # 5   1001 13057 2014-01-02        1  2013-01-31          2
    # 6   1002 13145 2014-01-02        1  2014-01-02          1
    # 7   1002 13166 2014-01-03        1  2014-01-02          1
    # 8   1002 13229 2014-01-03        1  2014-01-02          2
    # 9   1002 13057 2014-01-03        1  2014-01-02          3
    # 10  1002 13048 2014-01-04        1  2014-01-03          1
    

    cbind 返回一个全新的对象。如果您想将新列通过引用添加到df_sales,请改用:=。这里有很多在 SO 上使用它的例子,在 new HTML vignettes 下也有解释。

    【讨论】:

    • idx = df_supply[df_sales, roll=Inf, which=TRUE],此行抛出错误,因为实际数据集以 ITEM 为因子。尝试将 STORE 转换为一个因子,因为实际 ITEM id 具有因子值,因此 ITEM 不能被视为数字。我面临以下错误: bmerge 中的错误(i
    【解决方案2】:

    您可以尝试以下方法,使用 merge 和相关排序 (order):

    # order the data.frames
    df_sales <- df_sales[order(-df_sales$STORE, -df_sales$ITEM, df_sales$DATE_SALE, decreasing=T), ]
    df_supply <- df_supply[order(-df_supply$STORE, -df_supply$ITEM, df_supply$DATE_SUPPLY, decreasing=T), ]
    
    # merge the data.frames
    res <- merge(df_sales, df_supply, by=c("STORE","ITEM"), all=T)
    
    # keep only records with DATE_SUPPLY anterior to DATE_SALE
    res <- res[with(res, DATE_SUPPLY <= DATE_SALE), ]
    
    # remove duplicates (based on STORE, ITEM and DATE_SALE)
    res <- res[!duplicated(res[, 1:3]), ]
    
    res
       # STORE  ITEM  DATE_SALE QNT_SALE DATE_SUPPLY QNT_SUPPLY
    # 1   1001 13048 2014-01-02        1  2013-01-31          2
    # 2   1001 13048 2014-01-01        1  2013-01-31          2
    # 3   1001 13057 2014-01-02        1  2013-01-31          2
    # 4   1001 13057 2014-01-01        1  2013-01-31          2
    # 5   1001 13082 2014-01-02        1  2014-01-01          1
    # 7   1002 13048 2014-01-04        1  2014-01-03          1
    # 8   1002 13057 2014-01-03        1  2014-01-02          3
    # 9   1002 13145 2014-01-02        1  2014-01-02          1
    # 10  1002 13166 2014-01-03        1  2014-01-02          1
    # 11  1002 13229 2014-01-03        1  2014-01-02          2
    

    【讨论】:

    • 我不知道这将如何在具有不匹配日期的不同数据集上执行,但对于这个示例,它可以工作
    • 这就是示例必须具有代表性的原因 ;-)
    • @akrun 这确实是一个滚动连接问题,尤其是在被标记为data.table 时,但由于某种原因我试图解决它的尝试没有成功。你试过了吗?
    • @DavidArenburg 不,我没试过。
    • 我写了一个解决方案,但由于某种原因无法填充所有字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多