在 R 中合并两个数据帧时进行聚合
Aggregating while merging two dataframes in R
最终目标是对 product_info
中每条记录的总数量 (transact_data$qty
) 求和,其中 transact_data$productId
存在于 product_info
中,其中 [=17] =] 介于 product_info$beg_date
和 product_info$end_date
之间。
数据帧如下:
product_info <- data.frame(productId = c("A", "B", "A", "C","C","B"),
old_price = c(0.5,0.10,0.11,0.12,0.3,0.4),
new_price = c(0.7,0.11,0.12,0.11,0.2,0.3),
beg_date = c("2014-05-01", "2014-06-01", "2014-05-01", "2014-06-01","2014-05-01", "2014-06-01"),
end_date = c("2014-05-31", "2014-06-31", "2014-05-31", "2014-06-31","2014-05-31", "2014-06-31"), stringsAsFactors=FALSE)
transact_data <- data.frame(productId=c('A', 'B','A', 'C','A', 'B','C', 'B','A', 'C','A', 'B'),
date=c("2014-05-05", "2014-06-22", "2014-07-05", "2014-08-31","2014-05-03", "2014-02-22",
"2014-05-21", "2014-06-19", "2014-03-09", "2014-06-22","2014-04-03", "2014-07-08"),
qty =c(12,15,5,21,13,17,2,5,11,9,6,4), stringsAsFactors=FALSE)
我的第一步是通过 productId 合并两个数据框:
sku_transact_merge <-merge(x=product_info, y=transact_data, by = c("productId"))
下一步是计算数量总和:
sku_transact_merge$total_qty <- ifelse(sku_transact_merge$date >= sku_transact_merge$beg_date &
sku_transact_merge$date <= sku_transact_merge$end_date,
aggregate(qty ~ productId+beg_date+end_date,
data= sku_transact_merge, sum), 0)
结果不是我想要的,我收到一条错误消息
(list) object cannot be coerced to type 'double'
任何关于如何正确执行此逻辑的指示都将不胜感激!
一种方法是遍历 product_info
中的元素,确定 transact_data
中的所有匹配产品并求和它们的数量:
sapply(seq(nrow(product_info)), function(x) {
d <- product_info[x,]
sum(transact_data$qty[transact_data$productId == d$productId &
transact_data$date >= d$beg_date &
transact_data$date <= d$end_date])
})
# [1] 25 20 25 9 2 20
如果需要,您可以将其添加为 product_info
中的新列。
product_info$total_qty <- aggregate(col~row,which(outer(product_info$productId,transact_data$productId,`==`)&outer(product_info$beg_date,transact_data$date,`<=`)&outer(product_info$end_date,transact_data$date,`>=`),arr.ind=T),function(x) sum(transact_data$qty[x]))$col;
product_info;
## productId old_price new_price beg_date end_date total_qty
## 1 A 0.50 0.70 2014-05-01 2014-05-31 25
## 2 B 0.10 0.11 2014-06-01 2014-06-31 20
## 3 A 0.11 0.12 2014-05-01 2014-05-31 25
## 4 C 0.12 0.11 2014-06-01 2014-06-31 9
## 5 C 0.30 0.20 2014-05-01 2014-05-31 2
## 6 B 0.40 0.30 2014-06-01 2014-06-31 20
说明
首先,为三个匹配条件中的每一个构造一个逻辑矩阵,使用outer()
将product_info
中的每条记录与transact_data
中的每条记录进行比较。这三个逻辑矩阵被逻辑与在一起,形成一个最终的逻辑矩阵,表示哪些记录组合匹配。
outer(product_info$productId,transact_data$productId,`==`)
&outer(product_info$beg_date,transact_data$date,`<=`)
&outer(product_info$end_date,transact_data$date,`>=`)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [2,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## [3,] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [4,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
## [5,] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
## [6,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
然后,通过使用 arr.ind=T
调用 which()
来确定具有 TRUE
的行和列索引。行索引表示来自 product_info
的匹配记录(因为它位于 outer()
调用的左侧),列索引表示来自 transact_data
.
的匹配记录
which(...,arr.ind=T)
## row col
## [1,] 1 1
## [2,] 3 1
## [3,] 2 2
## [4,] 6 2
## [5,] 1 5
## [6,] 3 5
## [7,] 5 7
## [8,] 2 8
## [9,] 6 8
## [10,] 4 10
因为我们想为 product_info
中的每条记录从 transact_data
中求和 qty
个值,我们可以 aggregate()
the col
indexes grouping by row
by writing a custom aggregation function to index transact_data$qty
with the col
indexes and sum()
将它们 return 的单个值每个 row
.
aggregate(col~row,...,function(x) sum(transact_data$qty[x]))
## row col
## 1 1 25
## 2 2 20
## 3 3 25
## 4 4 9
## 5 5 2
## 6 6 20
最后我们可以将结果直接赋值给product_info$total_qty
完成求解
product_info$total_qty <- ...$col;
我不完全确定它是否保证 aggregate()
将始终 return 其结果按分组列排序。我刚刚在 .
问了这个问题
此外,我刚刚意识到,如果 product_info
中的所有记录在 transact_data
中没有至少一个匹配记录,直接赋值将会失败。
如果违反了其中任何一个假设,则可以按如下方式修复解决方案:
product_info$total_qty <- with(aggregate(col~row,which(outer(product_info$productId,transact_data$productId,`==`)&outer(product_info$beg_date,transact_data$date,`<=`)&outer(product_info$end_date,transact_data$date,`>=`),arr.ind=T),function(x) sum(transact_data$qty[x])),col[match(1:nrow(product_info),row)]);
product_info;
## productId old_price new_price beg_date end_date total_qty
## 1 A 0.50 0.70 2014-05-01 2014-05-31 25
## 2 B 0.10 0.11 2014-06-01 2014-06-31 20
## 3 A 0.11 0.12 2014-05-01 2014-05-31 25
## 4 C 0.12 0.11 2014-06-01 2014-06-31 9
## 5 C 0.30 0.20 2014-05-01 2014-05-31 2
## 6 B 0.40 0.30 2014-06-01 2014-06-31 20
现在,我们必须构造一个长度等于 product_info
和 match()
the qty
sums (which are inside col
) to their corresponding indexes (inside row
), with a little help from with()
.[= 中的行数的完整向量,而不是取消引用 $col
的最后一步52=]
product_info$total_qty <- with(...,col[match(1:nrow(product_info),row)]);
这可能是使用dplyr()
的另一种方法(如果您的数据集很大,这应该有效)
library(dplyr)
df = subset(sku_transact_merge, date > beg_date & date < end_date)
df = subset(df, select= -c(date))
out = unique(df %>% group_by(productId,old_price) %>% mutate(qty = sum(qty)))
#> out
#Source: local data frame [6 x 6]
#Groups: productId, old_price
#productId old_price new_price beg_date end_date qty
#1 A 0.50 0.70 2014-05-01 2014-05-31 25
#2 A 0.11 0.12 2014-05-01 2014-05-31 25
#3 B 0.10 0.11 2014-06-01 2014-06-31 20
#4 B 0.40 0.30 2014-06-01 2014-06-31 20
#5 C 0.12 0.11 2014-06-01 2014-06-31 9
#6 C 0.30 0.20 2014-05-01 2014-05-31 2
否则你可以使用 data.table
library(data.table)
out = setDT(df)[, list(qtynew = sum(qty)), by = list(productId, old_price)]
#> out
# productId old_price qtynew
#1: A 0.50 25
#2: A 0.11 25
#3: B 0.10 20
#4: B 0.40 20
#5: C 0.12 9
#6: C 0.30 2
最终目标是对 product_info
中每条记录的总数量 (transact_data$qty
) 求和,其中 transact_data$productId
存在于 product_info
中,其中 [=17] =] 介于 product_info$beg_date
和 product_info$end_date
之间。
数据帧如下:
product_info <- data.frame(productId = c("A", "B", "A", "C","C","B"),
old_price = c(0.5,0.10,0.11,0.12,0.3,0.4),
new_price = c(0.7,0.11,0.12,0.11,0.2,0.3),
beg_date = c("2014-05-01", "2014-06-01", "2014-05-01", "2014-06-01","2014-05-01", "2014-06-01"),
end_date = c("2014-05-31", "2014-06-31", "2014-05-31", "2014-06-31","2014-05-31", "2014-06-31"), stringsAsFactors=FALSE)
transact_data <- data.frame(productId=c('A', 'B','A', 'C','A', 'B','C', 'B','A', 'C','A', 'B'),
date=c("2014-05-05", "2014-06-22", "2014-07-05", "2014-08-31","2014-05-03", "2014-02-22",
"2014-05-21", "2014-06-19", "2014-03-09", "2014-06-22","2014-04-03", "2014-07-08"),
qty =c(12,15,5,21,13,17,2,5,11,9,6,4), stringsAsFactors=FALSE)
我的第一步是通过 productId 合并两个数据框:
sku_transact_merge <-merge(x=product_info, y=transact_data, by = c("productId"))
下一步是计算数量总和:
sku_transact_merge$total_qty <- ifelse(sku_transact_merge$date >= sku_transact_merge$beg_date &
sku_transact_merge$date <= sku_transact_merge$end_date,
aggregate(qty ~ productId+beg_date+end_date,
data= sku_transact_merge, sum), 0)
结果不是我想要的,我收到一条错误消息
(list) object cannot be coerced to type 'double'
任何关于如何正确执行此逻辑的指示都将不胜感激!
一种方法是遍历 product_info
中的元素,确定 transact_data
中的所有匹配产品并求和它们的数量:
sapply(seq(nrow(product_info)), function(x) {
d <- product_info[x,]
sum(transact_data$qty[transact_data$productId == d$productId &
transact_data$date >= d$beg_date &
transact_data$date <= d$end_date])
})
# [1] 25 20 25 9 2 20
如果需要,您可以将其添加为 product_info
中的新列。
product_info$total_qty <- aggregate(col~row,which(outer(product_info$productId,transact_data$productId,`==`)&outer(product_info$beg_date,transact_data$date,`<=`)&outer(product_info$end_date,transact_data$date,`>=`),arr.ind=T),function(x) sum(transact_data$qty[x]))$col;
product_info;
## productId old_price new_price beg_date end_date total_qty
## 1 A 0.50 0.70 2014-05-01 2014-05-31 25
## 2 B 0.10 0.11 2014-06-01 2014-06-31 20
## 3 A 0.11 0.12 2014-05-01 2014-05-31 25
## 4 C 0.12 0.11 2014-06-01 2014-06-31 9
## 5 C 0.30 0.20 2014-05-01 2014-05-31 2
## 6 B 0.40 0.30 2014-06-01 2014-06-31 20
说明
首先,为三个匹配条件中的每一个构造一个逻辑矩阵,使用outer()
将product_info
中的每条记录与transact_data
中的每条记录进行比较。这三个逻辑矩阵被逻辑与在一起,形成一个最终的逻辑矩阵,表示哪些记录组合匹配。
outer(product_info$productId,transact_data$productId,`==`)
&outer(product_info$beg_date,transact_data$date,`<=`)
&outer(product_info$end_date,transact_data$date,`>=`)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [2,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## [3,] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [4,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
## [5,] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
## [6,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
然后,通过使用 arr.ind=T
调用 which()
来确定具有 TRUE
的行和列索引。行索引表示来自 product_info
的匹配记录(因为它位于 outer()
调用的左侧),列索引表示来自 transact_data
.
which(...,arr.ind=T)
## row col
## [1,] 1 1
## [2,] 3 1
## [3,] 2 2
## [4,] 6 2
## [5,] 1 5
## [6,] 3 5
## [7,] 5 7
## [8,] 2 8
## [9,] 6 8
## [10,] 4 10
因为我们想为 product_info
中的每条记录从 transact_data
中求和 qty
个值,我们可以 aggregate()
the col
indexes grouping by row
by writing a custom aggregation function to index transact_data$qty
with the col
indexes and sum()
将它们 return 的单个值每个 row
.
aggregate(col~row,...,function(x) sum(transact_data$qty[x]))
## row col
## 1 1 25
## 2 2 20
## 3 3 25
## 4 4 9
## 5 5 2
## 6 6 20
最后我们可以将结果直接赋值给product_info$total_qty
完成求解
product_info$total_qty <- ...$col;
我不完全确定它是否保证 aggregate()
将始终 return 其结果按分组列排序。我刚刚在
此外,我刚刚意识到,如果 product_info
中的所有记录在 transact_data
中没有至少一个匹配记录,直接赋值将会失败。
如果违反了其中任何一个假设,则可以按如下方式修复解决方案:
product_info$total_qty <- with(aggregate(col~row,which(outer(product_info$productId,transact_data$productId,`==`)&outer(product_info$beg_date,transact_data$date,`<=`)&outer(product_info$end_date,transact_data$date,`>=`),arr.ind=T),function(x) sum(transact_data$qty[x])),col[match(1:nrow(product_info),row)]);
product_info;
## productId old_price new_price beg_date end_date total_qty
## 1 A 0.50 0.70 2014-05-01 2014-05-31 25
## 2 B 0.10 0.11 2014-06-01 2014-06-31 20
## 3 A 0.11 0.12 2014-05-01 2014-05-31 25
## 4 C 0.12 0.11 2014-06-01 2014-06-31 9
## 5 C 0.30 0.20 2014-05-01 2014-05-31 2
## 6 B 0.40 0.30 2014-06-01 2014-06-31 20
现在,我们必须构造一个长度等于 product_info
和 match()
the qty
sums (which are inside col
) to their corresponding indexes (inside row
), with a little help from with()
.[= 中的行数的完整向量,而不是取消引用 $col
的最后一步52=]
product_info$total_qty <- with(...,col[match(1:nrow(product_info),row)]);
这可能是使用dplyr()
的另一种方法(如果您的数据集很大,这应该有效)
library(dplyr)
df = subset(sku_transact_merge, date > beg_date & date < end_date)
df = subset(df, select= -c(date))
out = unique(df %>% group_by(productId,old_price) %>% mutate(qty = sum(qty)))
#> out
#Source: local data frame [6 x 6]
#Groups: productId, old_price
#productId old_price new_price beg_date end_date qty
#1 A 0.50 0.70 2014-05-01 2014-05-31 25
#2 A 0.11 0.12 2014-05-01 2014-05-31 25
#3 B 0.10 0.11 2014-06-01 2014-06-31 20
#4 B 0.40 0.30 2014-06-01 2014-06-31 20
#5 C 0.12 0.11 2014-06-01 2014-06-31 9
#6 C 0.30 0.20 2014-05-01 2014-05-31 2
否则你可以使用 data.table
library(data.table)
out = setDT(df)[, list(qtynew = sum(qty)), by = list(productId, old_price)]
#> out
# productId old_price qtynew
#1: A 0.50 25
#2: A 0.11 25
#3: B 0.10 20
#4: B 0.40 20
#5: C 0.12 9
#6: C 0.30 2