2012-08-02 39 views
8

Tôi có một khung dữ liệu rất lớn trong R và muốn tổng hợp hai cột cho mỗi giá trị khác biệt trong các cột khác, ví dụ như chúng tôi đã có dữ liệu của một khung dữ liệu giao dịch trong các cửa hàng khác nhau trong một ngày như sauTổng bằng giá trị cột riêng biệt trong R

shop <- data.frame('shop_id' = c(1, 1, 1, 2, 3, 3), 
    'shop_name' = c('Shop A', 'Shop A', 'Shop A', 'Shop B', 'Shop C', 'Shop C'), 
    'city' = c('London', 'London', 'London', 'Cardiff', 'Dublin', 'Dublin'), 
    'sale' = c(12, 5, 9, 15, 10, 18), 
    'profit' = c(3, 1, 3, 6, 5, 9)) 

đó là:

shop_id shop_name city  sale profit 
    1  Shop A  London 12 3 
    1  Shop A  London 5 1 
    1  Shop A  London 9 3 
    2  Shop B  Cardiff 15 6 
    3  Shop C  Dublin 10 5 
    3  Shop C  Dublin 18 9 

và tôi muốn tổng hợp việc bán và lợi nhuận cho mỗi cửa hàng để cung cấp cho:

shop_id shop_name city  sale profit 
    1  Shop A  London 26 7 
    2  Shop B  Cardiff 15 6 
    3  Shop C  Dublin 28 14 

Tôi hiện đang sử dụng đoạn mã sau để làm điều này:

shop_day <-ddply(shop, "shop_id", transform, sale=sum(sale), profit=sum(profit)) 
shop_day <- subset(shop_day, !duplicated(shop_id)) 

mà làm việc hoàn toàn tốt, nhưng như tôi đã nói dataframe của tôi là lớn (140.000 hàng, 37 cột và gần 100.000 hàng duy nhất mà tôi muốn tổng hợp) và mã của tôi mất nhiều thời gian để chạy và sau đó cuối cùng nói rằng nó đã hết bộ nhớ.

Có ai biết cách hiệu quả nhất để thực hiện việc này không.

Cảm ơn trước!

+2

... Tôi cảm thấy câu trả lời 'data.table' sắp tới ... –

Trả lời

13

** Bảng buộc dữ liệu câu trả lời **

> library(data.table) 
data.table 1.8.0 For help type: help("data.table") 
> shop.dt <- data.table(shop) 
> shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id'] 
    shop_id sale profit 
[1,]  1 26  7 
[2,]  2 15  6 
[3,]  3 28  14 
> 

Những âm thanh tốt và tốt cho đến khi mọi thứ trở nên lớn hơn ...

shop <- data.frame(shop_id = letters[1:10], profit=rnorm(1e7), sale=rnorm(1e7)) 
shop.dt <- data.table(shop) 

> system.time(ddply(shop, .(shop_id), summarise, sale=sum(sale), profit=sum(profit))) 
    user system elapsed 
    4.156 1.324 5.514 
> system.time(shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id']) 
    user system elapsed 
    0.728 0.108 0.840 
> 

Bạn nhận được tốc độ tăng thêm nếu bạn tạo data.table bằng một khóa:

shop.dt <- data.table(shop, key='shop_id') 

> system.time(shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id']) 
    user system elapsed 
    0.252 0.084 0.336 
> 
+0

Lưu ý rằng Justin đang sử dụng' summaryise' thay vì 'transform' trong lệnh' ddply'; thay đổi đó có thể đủ để mã của bạn hoạt động mà không có lỗi bộ nhớ, mặc dù các giải pháp khác chắc chắn nhanh hơn. – Aaron

+0

@Aaron Cảm ơn! Tôi để lại lời giải thích đó vì có một câu trả lời trước đó giải thích nó. Tuy nhiên đó là kể từ khi xóa! – Justin

+0

Cảm ơn Justin, nhanh hơn rất nhiều. Một câu hỏi khác, có cách nào để giữ các cột khác (ví dụ: shop_name, thành phố) trong bảng dữ liệu cuối cùng không? Tôi có thể tham gia trở lại trên dataframe ban đầu để có được điều này nhưng sẽ được neater nếu có một cách để làm điều này trong truy vấn ban đầu. – user1165199

3

Dưới đây là cách sử dụng cơ sở R để tăng tốc các hoạt động như sau:

idx <- split(1:nrow(shop), shop$shop_id) 
a2 <- data.frame(shop_id=sapply(idx, function(i) shop$shop_id[i[1]]), 
       sale=sapply(idx, function(i) sum(shop$sale[i])), 
       profit=sapply(idx, function(i) sum(shop$profit[i]))) 

Thời gian giảm xuống 0,75 giây so với 5,70 giây cho phiên bản tóm tắt hoàn toàn trên hệ thống của tôi.

+0

Nếu tôi có nhiều cột như bán hàng và lợi nhuận trong ví dụ trên mà tôi muốn tổng hợp, có thể gọi một hàm duy nhất để kết hợp dòng thứ ba và thứ tư trong mã trên vào một dòng duy nhất. – discipulus

+1

Không thực sự sử dụng phương pháp chính xác này, nhưng có nhiều cách để làm điều đó. Bắt đầu một câu hỏi mới với ví dụ có thể tái sản xuất tối thiểu và bạn sẽ nhận được nhiều đề xuất. – Aaron

Các vấn đề liên quan