2014-08-28 64 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