R: Avoid using a loop or line

I am following two dataframes df_sales and df_supply .

I want to merge sale for delivery in such a way that my df_sales table has DATE_SUPPLY and QNT_SUPPLY from df_supply below conditions

* Condition : DATE_SUPPLY must be the last DATE_SUPPLY of the corresponding "ITEM" for the corresponding "STORE", i.e.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)*

This can be possible with the string apply function, or simply by writing a loop. But I have a huge array of data, so I don't want to loop.

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

      

+3


source to share


2 answers


Here's what you can try using merge

and the appropriate order ( 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

      

+3


source


Using sliding joints from 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, with=FALSE])
#    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

returns a completely new object. If you want to add new columns by reference instead df_sales

, use :=

. There are many examples of using this here on SO and also explained in the new HTML Widgets .

+5


source







All Articles