【问题标题】:Join on 4 variables then group on fewer variables using data.table加入 4 个变量,然后使用 data.table 对更少的变量进行分组
【发布时间】:2017-03-03 21:02:31
【问题描述】:

这个帖子是我之前的帖子 Join then mutate using data.table without intermediate table 的延续。

在那个线程中,我使用查找表来更改收入和数量,然后将结果除以.N,这样当我汇总产品时,我就不会看到虚增的值。

根据该线程专家的建议,我不想指望用于连接的所有四个变量,即PO_IDSO_IDF_YearProduct_ID,但只有SO_IDF_YearProduct_ID

问题:我怎样才能使用data.table做到这一点?

这是我的数据和代码:

这是我使用dplyr的数据和解决方案

输入

DFI = structure(list(PO_ID = c("P1234", "P1234", "P1234", "P1234", 
"P1234", "P1234", "P2345", "P2345", "P3456", "P4567"), SO_ID = c("S1", 
"S1", "S2", "S2", "S2", "S2", "S3", "S3", "S7", "S10"), F_Year = c(2012, 
2012, 2013, 2013, 2013, 2013, 2011, 2011, 2014, 2015), Product_ID = c("385X", 
"385X", "450X", "450X", "450X", "900X", "3700", "3700", "A11U", 
"2700"), Revenue = c(1, 2, 3, 34, 34, 6, 7, 88, 9, 100), Quantity = c(1, 
2, 3, 8, 8, 6, 7, 8, 9, 40), Location1 = c("MA", "NY", "WA", 
"NY", "WA", "NY", "IL", "IL", "MN", "CA")), .Names = c("PO_ID", 
"SO_ID", "F_Year", "Product_ID", "Revenue", "Quantity", "Location1"
), row.names = c(NA, 10L), class = "data.frame")

查表

DF_Lookup = structure(list(PO_ID = c("P1234", "P1234", "P1234", "P2345", 
"P2345", "P3456", "P4567"), SO_ID = c("S1", "S2", "S2", "S3", 
"S4", "S7", "S10"), F_Year = c(2012, 2013, 2013, 2011, 2011, 
2014, 2015), Product_ID = c("385X", "450X", "900X", "3700", "3700", 
"A11U", "2700"), Revenue = c(50, 70, 35, 100, -50, 50, 100), 
    Quantity = c(3, 20, 20, 20, -10, 20, 40)), .Names = c("PO_ID", 
"SO_ID", "F_Year", "Product_ID", "Revenue", "Quantity"), row.names = c(NA, 
7L), class = "data.frame")

这是我使用dplyr修改后的代码:

DF_Generated <- DFI %>% 
  left_join(DF_Lookup,by = c("PO_ID", "SO_ID", "F_Year", "Product_ID")) %>%
  dplyr::group_by(SO_ID, F_Year, Product_ID) %>%
  dplyr::mutate(Count = n()) %>%
  dplyr::ungroup()%>%
  dplyr::mutate(Revenue = Revenue.y/Count, Quantity = Quantity.y/Count) %>%
  dplyr::select(PO_ID:Product_ID,Location1,Revenue,Quantity)

请注意group_by 的输入已更改。

预期输出:

DF_Generated = structure(list(PO_ID = c("P1234", "P1234", "P1234", "P1234", 
"P1234", "P1234", "P2345", "P2345", "P3456", "P4567"), SO_ID = c("S1", 
"S1", "S2", "S2", "S2", "S2", "S3", "S3", "S7", "S10"), F_Year = c(2012, 
2012, 2013, 2013, 2013, 2013, 2011, 2011, 2014, 2015), Product_ID = c("385X", 
"385X", "450X", "450X", "450X", "900X", "3700", "3700", "A11U", 
"2700"), Location1 = c("MA", "NY", "WA", "NY", "WA", "NY", "IL", 
"IL", "MN", "CA"), Revenue = c(25, 25, 23.3333333333333, 23.3333333333333, 
23.3333333333333, 35, 50, 50, 50, 100), Quantity = c(1.5, 1.5, 
6.66666666666667, 6.66666666666667, 6.66666666666667, 20, 10, 
10, 20, 40)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-10L), .Names = c("PO_ID", "SO_ID", "F_Year", "Product_ID", "Location1", 
"Revenue", "Quantity"))

注意:请注意,我不想创建中间变量,因为实际数据量太大,这可能不可行。

【问题讨论】:

  • 你试过什么,为什么没用?
  • @mtoto - 我尝试使用dplyr,这是我在上面发布的。正如我们所说,我仍在尝试使用data.table 来完成它,并且不断出错。正如我所说,我是初学者,对data.table 不是很熟悉。
  • 我猜,加入第四列并没有什么意义。如果我把它排除在连接之外,我会得到你想要的结果:DFI[DF_Lookup, on=.(SO_ID, F_Year, Product_ID), `:=`(nr = i.Revenue/.N, nq = i.Quantity/.N), by=.EACHI][]
  • @Frank - 感谢您的帮助,但这取决于这三列是复合键。在我的实际数据中并非如此。要我更改查找表并重新发布吗?
  • 当然,我不是 sql 大师,所以不知道复合性在这里有多重要。

标签: r data.table dplyr


【解决方案1】:

这应该可以满足您的需求

library(data.table)
setDT(DFI)
DFI[ , c("Revenue", "Quantity") := NULL]

setDT(DF_Lookup)

dat = merge(DF_Lookup, DFI, by = c("PO_ID", "SO_ID", "F_Year", "Product_ID"))
dat = dat[ , .(Revenue = Revenue/.N, Quantity = Quantity/.N, Location1), by = .(PO_ID, SO_ID, F_Year, Product_ID)]

dat
    PO_ID SO_ID F_Year Product_ID   Revenue  Quantity Location1
 1: P1234    S1   2012       385X  25.00000  1.500000        MA
 2: P1234    S1   2012       385X  25.00000  1.500000        NY
 3: P1234    S2   2013       450X  23.33333  6.666667        WA
 4: P1234    S2   2013       450X  23.33333  6.666667        NY
 5: P1234    S2   2013       450X  23.33333  6.666667        WA
 6: P1234    S2   2013       900X  35.00000 20.000000        NY
 7: P2345    S3   2011       3700  50.00000 10.000000        IL
 8: P2345    S3   2011       3700  50.00000 10.000000        IL
 9: P3456    S7   2014       A11U  50.00000 20.000000        MN
10: P4567   S10   2015       2700 100.00000 40.000000        CA

【讨论】:

  • 感谢您的帮助。我相信你的第二行你打算做by = .(SO_ID, F_Year, Product_ID) [没有PO_ID]。对吗?
  • length(some_col) 在此处使用时为 .N
  • @watchtower 当然,我们可以将所有内容保存为 DF_Lookup。所以只需写DF_Lookup = merge(DF_Lookup, ...),然后用DF_Lookup替换所有dat
  • @watchtower 如果您只是将 PO_ID 留在代码之外,那么最后将不再有该列。
  • @watchtower 你可以这样做dat = dat[ , .(PO_ID,Revenue = Revenue/length(Location1), Quantity = Quantity/length(Location1), Location1), by = .(SO_ID, F_Year, Product_ID)]
猜你喜欢
  • 2021-01-03
  • 2017-01-08
  • 2013-07-18
  • 2021-07-03
  • 2019-12-28
  • 2020-04-01
  • 2015-02-07
  • 1970-01-01
  • 2021-03-22
相关资源
最近更新 更多