2014-08-28 63 views
0

我正在尋找一種快速有效的方法來計算下面描述的問題。任何幫助將不勝感激,在此先感謝!向量化「查找」功能的正確方法

我有幾個非常大的csv文件,它們具有關於同一個對象的不同信息,但是在我的最終計算中,我需要不同表中的所有屬性。我試圖計算大量變電站的負載,首先我列出了一個獨特的變電站清單;

Unique_Substations <- data.frame(Name = c("SubA", "SubB", "SubC", "SubD")) 

在另一個列表中,我有關於這些變電站後面客戶的信息;

Customer_Information <- data.frame(
    Customer = 1001:1010, 
    SubSt_Nm = sample(unique(Unique_Substations$Name), 10, replace = TRUE), 
    HouseHoldType = sample(1:2, 10, replace = TRUE) 
) 

而在另一份名單我有信息,讓我們說,對這些客戶的屋頂太陽能電池板(不同年份);

Solar_Panels <- data.frame(
    Customer = sample(1001:1010, 10, replace = TRUE), 
    SolarPanelYear1 = sample(10:20, 10, replace = TRUE), 
    SolarPanelYear2 = sample(15:20, 10, replace = TRUE) 
) 

現在我想看看每個變電站每年的負載是多少。我有一個家庭負載和一個太陽能電池板負載正常化的每種類型的家庭或solarpanel;

SolarLoad <- data.frame(Load = c(0, -10, -10, 5)) 
HouseHoldLoad <- data.frame(Type1 = c(1, 3, 5, 2), Type2 = c(3, 5, 6, 1)) 

所以現在我必須匹配這些列表;

ML_SubSt_Cust <- sapply(Unique_Substations$Name, 
         function(x) which(Customer_Information$SubSt_Nm %in% x == TRUE)) 

ML_Cust_SolarP <- sapply(Customer_Information$Customer, 
         function(x) which(Solar_Panels$Customer %in% x == TRUE)) 

(這裏我用的which(xxx %in% x == TRUE)方法,因爲我需要多比賽和match()只返回一個匹配

現在我們來到我的大問題(但可能不是我唯一的,最後用這種方法的問題)我想計算每個變電站每年的最大負載,爲此我首先編寫了一個for循環,通過Unique_Substations列表循環,這當然是非常低效的。之後我嘗試使用outer()來加速它,但是我認爲我沒有正確地將我的功能向量化,我的最大功能如下所示(我只寫了太陽能電池板部分以保留我簡單);

GetMax <- function(i, Yr) { 
    max(sum(Solar_Panels[unlist(ML_Cust_SolarP[ML_SubSt_Cust[[i]]], use.names= FALSE),Yr])*SolarLoad) 
} 

我確定這根本沒有效率,但我不知道如何以任何其他方式做到這一點。

爲了得到我的最終結果,我使用了一個外部函數;

Results <- outer(1:nrow(Unique_Substations), 1:2, Vectorize(GetMax)) 

在我的例子所有這些數據的幀是非常非常大(每個左右40000行),所以我真正需要的參與功能的一些很好的優化。我試圖想方法來矢量化函數,但我無法解決這個問題。任何幫助,將不勝感激。

編輯:

現在,我完全理解接受awnser我還有一個問題。我的實際Customer_Information是188K行長,我的實際HouseHoldLoad是53K行長。不用說這不是merge()非常好。是否有另一種解決方案,不需要merge()或循環太慢?

+0

首先,你不需要'data.frames',因爲只有一個數據類型每個對象。向量和矩陣就足夠了。接下來,不是'which(foo%in%bar == TRUE)',而只是'which(bar == foo)'(其中'foo'是一個標量,'bar'是你的向量或矩陣)。 – 2014-08-28 11:20:47

+1

@CarlWitthoft'which(foo%in%bar == TRUE)'與'which(foo%in%bar)'相同,而不是'which(bar == foo)'。拿'bar = c(0,1)'和'foo = c(1,0)',差別很明顯。我同意你可以在'foo'只包含一個元素時使用,但它們不一樣。 – 2014-08-28 11:52:57

+0

@JorisMeys謝謝 - 好點 – 2014-08-28 12:37:39

回答

2

第一次:set.seed()生成隨機數據時!在您爲這些結果編碼之前,我做了set.seed(1000)

我覺得有點merge -ing和dplyr可以在這裏幫助。首先,我們得到的數據轉換成一個更好的狀態:

library(dplyr) 
library(reshape2) 

HouseHoldLoad <- melt(HouseHoldLoad, value.name="Load") %>% 
    select(HouseHoldType=variable, Load) %>% 
    mutate(HouseHoldType=gsub("Type", "", HouseHoldType)) 

Solar_Panels <- melt(Solar_Panels, id.vars="Customer", 
        value.name="SPYearVal") %>% 
    select(Customer, SolarPanelYear=variable, SPYearVal) %>% 
    mutate(SolarPanelYear=gsub("SolarPanelYear", "", SolarPanelYear)) 

dat <- merge(Customer_Information, Solar_Panels, by="Customer") 

這給了我們:

## Customer SubSt_Nm HouseHoldType SolarPanelYear SPYearVal 
## 1  1001  SubB    1    1  16 
## 2  1001  SubB    1    2  18 
## 3  1001  SubB    1    2  16 
## 4  1001  SubB    1    1  20 
## 5  1002  SubD    2    1  16 
## 6  1002  SubD    2    1  13 
## 7  1002  SubD    2    2  20 
## 8  1002  SubD    2    2  18 
## 9  1003  SubA    1    2  15 
## 10  1003  SubA    1    1  16 
## 11  1005  SubC    2    2  19 
## 12  1005  SubC    2    1  10 
## 13  1006  SubA    1    1  15 
## 14  1006  SubA    1    2  19 
## 15  1007  SubC    1    1  17 
## 16  1007  SubC    1    2  19 
## 17  1009  SubA    1    1  10 
## 18  1009  SubA    1    1  18 
## 19  1009  SubA    1    2  18 
## 20  1009  SubA    1    2  18 

現在我們只是一羣總結:

dat %>% group_by(SubSt_Nm, SolarPanelYear) %>% 
    summarise(mx=max(sum(SPYearVal)*SolarLoad)) 

## SubSt_Nm SolarPanelYear mx 
## 1  SubA    1 295 
## 2  SubA    2 350 
## 3  SubB    1 180 
## 4  SubB    2 170 
## 5  SubC    1 135 
## 6  SubC    2 190 
## 7  SubD    1 145 
## 8  SubD    2 190 

如果使用data.table VS數據幀即使有40K條目,它也應該很快。

UPDATE對於那些誰不能安裝dplyr,這只是使用reshape2(希望這是安裝)

library(reshape2) 

HouseHoldLoad <- melt(HouseHoldLoad, value.name="Load") 
colnames(HouseHoldLoad) <- c("HouseHoldType", "Load") 
HouseHoldLoad$HouseHoldType <- gsub("Type", "", HouseHoldLoad$HouseHoldType) 

Solar_Panels <- melt(Solar_Panels, id.vars="Customer", value.name="SPYearVal") 
colnames(Solar_Panels) <- c("Customer", "SolarPanelYear", "SPYearVal") 
Solar_Panels$SolarPanelYear <- gsub("SolarPanelYear", "", Solar_Panels$SolarPanelYear) 

dat <- merge(Customer_Information, Solar_Panels, by="Customer") 

rbind(by(dat, list(dat$SubSt_Nm, dat$SolarPanelYear), function(x) { 
    mx <- max(sum(x$SPYearVal) * SolarLoad) 
})) 

##  1 2 
## SubA 295 350 
## SubB 180 170 
## SubC 135 190 
## SubD 145 190 

如果你真的無法安裝甚至reshape2,那麼這個作品只基stats包:

colnames(HouseHoldLoad) <- c("Load.1", "Load.2") 
HouseHoldLoad <- reshape(HouseHoldLoad, varying=c("Load.1", "Load.2"), direction="long", timevar="HouseHoldType")[1:2] 

colnames(Solar_Panels) <- c("Customer", "SolarPanelYear.1", "SolarPanelYear.2") 
Solar_Panels <- reshape(Solar_Panels, varying=c("SolarPanelYear.1", "SolarPanelYear.2"), direction="long", timevar="SolarPanelYear")[1:2] 
colnames(Solar_Panels) <- c("Customer", "SPYearVal") 
Solar_Panels$SolarPanelYear <- gsub("^[0-9]+\\.", "", rownames(Solar_Panels)) 

dat <- merge(Customer_Information, Solar_Panels, by="Customer") 

rbind(by(dat, list(dat$SubSt_Nm, dat$SolarPanelYear), function(x) { 
    mx <- max(sum(x$SPYearVal) * SolarLoad) 
})) 

##  1 2 
## SubA 295 350 
## SubB 180 170 
## SubC 135 190 
## SubD 145 190 
+0

謝謝你的答案,但不知何故,我的工作電腦似乎無法安裝'dplyr'軟件包。此外,這個腳本將運行在遠程服務器上,我可悲的是無法安裝軟件包,有沒有辦法做到這一點,而無需dplyr? – 2014-08-28 13:43:43

+0

我不得不面對類似的情況(沒有樂趣被限制選項卡住)。現在答案中有兩個類似的解決方案。我沒有做任何時間安排,但我必須相信他們按照最快或最慢的順序,特別是大型數據集。另外,如果你可以設法使用'dplyr',你甚至可以利用數據庫來獲取數據庫(我假設你正在使用這個數據庫)。 – hrbrmstr 2014-08-28 16:46:04

+0

好的,非常感謝!我會試一試,並接受它的工作原理! – 2014-08-28 18:03:21