正确的矢量化方式"查找"功能

时间:2014-08-28 09:20:29

标签: r rstudio

我正在寻找一种快速有效的方法来计算下面描述的问题。任何帮助将不胜感激,提前谢谢!

我有几个非常大的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)
)

现在我想知道每年每个变电站的负荷是多少。我有一个家庭负载和太阳能电池板负载标准化为每种类型的家庭或太阳能板;

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()只返回一个匹配

现在我们终于回答了我的大问题(但可能不是我唯一的问题)。我想计算每个变电站每年的最大负荷。为此,我首先编写了一个循环遍历Unique_Substations列表的for循环,这当然效率很低。之后我尝试使用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行),所以我真的需要对所涉及的功能进行一些很好的优化。我试着想办法对函数进行矢量化,但是我无法解决这个问题。任何帮助将不胜感激。

编辑:

现在我完全理解了接受的芒果,我还有另外一个问题。我的实际Customer_Information长度为188k行,而我的实际HouseHoldLoad长度为53k行。毋庸置疑,这不是merge()。是否有另一个解决此问题的方法,不需要merge()或者太慢的循环?

1 个答案:

答案 0 :(得分: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条目也应该非常快。

更新对于无法安装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