2015-05-29 4 views
3

Конечная цель состоит в том, чтобы подвести общее количество (transact_data$qty) для каждой записи в product_info, где transact_data$productId существует в product_info, и где transact_data$date между product_info$beg_date и product_info$end_date.Агрегирование при объединении двух dataframes в R

В dataframes ниже:

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) 

Мой первый шаг должен был объединить оба dataframes по 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) 

Результат не то, что я хочу, и я получаю сообщение об ошибке

(список) объект не может быть принужден к типу «двойной»

Любые указатели о том, как правильно выполнить эту логику была бы оценена!

+0

Преднамеренно ли вы дублируете записи 'productId, beg_date, end_date' в' product_info' (т.е. 'A, 2014-05-01,2014-05-31' и' B, 2 014-06-01,2014-06-31')? Это приведет к дублированию записей в 'transact_data' путем вызова' merge() 'и, таким образом, суммируется несколько раз во время возможной' sum() ', что я не могу представить, было бы правильно. – bgoldst

+0

Yup тот был предназначенный. – BlackHat

+0

Вы хотите объединить эти дублированные значения 'qty'? Если ваш желаемый результат является уникальной таблицей 'productId, beg_date, end_date', тогда эти дублированные значения qty будут суммированы в одну и ту же выходную запись, которую я все еще не могу представить, будет правильным. Ваш желаемый результат не ясен для меня. – bgoldst

ответ

3

Это может быть другой способ сделать это с помощью 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 
+0

Что означает -6? Если он ограничивает мой результат матрицей 6x6, тогда он не будет масштабируемым, если у меня будет более 6 записей. Или это просто количество столбцов? – BlackHat

+0

Это может показаться глупым, но почему мы используем «=» для возврата в R. Почему бы не «<-»? Благодарю. – BlackHat

+0

в R сценариях как '=', так и '<-' могут использоваться как назначающие операторы. Я предпочитаю '=', потому что его просто набрать! если вам интересно узнать больше, проверьте это обсуждение [здесь] (http://stackoverflow.com/questions/1741820/assignment-operators-in-r-and) –

2

Один подход был бы перебрать элементы в 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 при желании.

+0

Спасибо. Я попробовал ваше решение и попытался добавить значения в новый столбец в product_info. Я получаю «уровни ошибок на уровне факторов разные» – BlackHat

+0

@ user3116753 попробуйте преобразовать переменные в строки с помощью функции 'as.character'. – josliber

1
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. Эти три логические матрицы логически-ANDed вместе, чтобы сформировать конечную логическую матрицу, представляющую, какие комбинации записей совпадают.

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 

Затем строк и столбцов индексов с TRUE констатированы через вызов which() с arr.ind=T. Индексы строк представляют собой совпадающие записи от 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 

Поскольку мы хотим подвести qty значения из transact_data для каждой записи в product_info, мы можем aggregate() в col индексов группирования по row путем написания пользовательской функции агрегации для индекса transact_data$qty с col индексами и sum() их возвращать одно значение для каждого 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() всегда будет возвращать ее результат упорядоченный по столбцу (ы) группировки. Я просто спросил об этом Does aggregate() guarantee that the result will be ordered by the grouping columns?.

Также я понял, что прямое присвоение не удастся, если не все записи в 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 

Теперь, вместо конечной стадии разыменования $col, мы должны построить полный вектор длины, равный числу из строк в product_info и match()qty суммы (которые находятся внутри col) до соответствующих им индексов (внутри row), с небольшой помощью от .

product_info$total_qty <- with(...,col[match(1:nrow(product_info),row)]); 
+1

Текущая машина исчерпала память, используя ваш метод, поэтому проверит на другом и вернется к вам. – BlackHat

+0

Нет. Мне нравится решение, но на моей машине на самом деле заканчивается память, когда я пытаюсь запустить это. Это не ваше решение. Эта машина должна идти. Спасибо за вашу помощь. – BlackHat

Смежные вопросы