在 R 中处理地理数据时提高性能
Posted
技术标签:
【中文标题】在 R 中处理地理数据时提高性能【英文标题】:Improving performance when working with geodata in R 【发布时间】:2014-09-20 21:31:20 【问题描述】:我编写了以下脚本来生成用于绘制上述地图的原始数据。问题是,对于 550,000 个数据点,这需要大约 2 小时才能在相对强大的机器上运行。但是,我是 R 新手,我想知道是否有任何优化的功能可以利用?
基本思想是,给定一组地理空间数据,将数据集拆分为 200 行,并将每一行拆分为一堆正方形。然后,您计算一行中每个方格中的值的总和。我在下面采用的方法是取正方形的“左上”点,计算正方形边缘的纬度/经度,并排除所有不在这些范围内的点,然后将剩余的点相加。不使用 PostGIS 这样的解决方案有没有更好的方法?
all.data <- read.csv("FrederictonPropertyTaxDiffCleanedv3.csv", header=TRUE,
stringsAsFactors=FALSE)
all.data$X <- as.numeric(all.data$X)
all.data$Y <- as.numeric(all.data$Y)
startEnd <- function(lats, lngs)
# Find the "upper left" (NW) and "bottom right" (SE) coordinates of a set of data.
#
# Args:
# lats: A list of latitude coordinates
# lngs: A list of longitude coordinates
#
# Returns:
# A list of values corresponding to the northwest-most and southeast-most coordinates
# Convert to real number and remove NA values
lats <- na.omit(as.numeric(lats))
lngs <- na.omit(as.numeric(lngs))
topLat <- max(lats)
topLng <- min(lngs)
botLat <- min(lats)
botLng <- max(lngs)
return(c(topLat, topLng, botLat, botLng))
startEndVals <- startEnd(all.data$Y, all.data$X)
startLat <- startEndVals[1]
endLat <- startEndVals[3]
startLng <- startEndVals[2]
endLng <- startEndVals[4]
num_intervals = 200.0
interval <- (startEndVals[1] - startEndVals[3]) / num_intervals
# testLng <- -66.6462379307115
# testLat <- 45.9581234392
# Prepare the data to be sent in
data <- all.data[,c("Y", "X", "levy2014_ha")]
sumInsideSquare <- function(pointLat, pointLng, interval, data)
# Sum all the values that fall within a square on a map given a point,
# an interval of the map, and data that contains lat, lng and the values
# of interest
colnames(data) <- c("lat", "lng", "value")
# Data east of point
data <- data[data$lng > pointLng,]
# Data west of point + interval
data <- data[data$lng < pointLng + interval,]
# Data north of point + interval (down)
data <- data[data$lat > pointLat - interval,]
# Data south of point
data <- data[data$lat < pointLat, ]
# Clean remaining data
data <- na.omit(data)
return(sum(data$value))
# Debugging
# squareSumTemp <- sumInsideSquare(testLat, testLng, interval, data)
# Given a start longitude and an end longitude, calculate an array of values
# corresponding to the sums for that latitude
calcSumLat <- function(startLng, endLng, lat, interval, data)
row <- c()
lng <- startLng
while (lng < endLng)
row <- c(row, sumInsideSquare(lat, lng, interval, data))
lng <- lng + interval
return(row)
# Debugging
# rowTemp <- calcSumLat(startLng, endLng, testLat, interval, data)
# write.csv(rowTemp, file = "Temp.csv", row.names = FALSE)
# Get each line of data to plot
lat <- startLat
rowCount <- 1
all.sums <- list()
while (lat > endLat)
col <- calcSumLat(startLng, endLng, lat, interval, data)
all.sums[[as.character(rowCount)]] <- col
lat <- lat - interval
rowCount <- rowCount + 1
# Convert to data frame
all.sums.frame <- data.frame(all.sums)
# Save to disk so I don't have to run it again
write.csv(all.sums.frame, file = "Levy2014Sums200.csv", row.names = FALSE)
【问题讨论】:
您是否尝试过使用Rprof
分析您的代码以找出花费最多时间的地方?
直到现在才知道 RProf - 来看看吧!
使用 RProf 很明显瓶颈在 sumInsideSquares 函数中。我重新编写了该函数,以便所有数据帧分段都发生在一行上,从而将时间缩短了一半。但是,仍然需要很长时间才能运行,所以我需要进一步优化它。我可能会开始研究 R 中的多线程,因为这将是它的主要候选者。
【参考方案1】:
最终自己找到了解决方案。它的关键是将 foreach 包与 doParallel 包一起使用,这样它就可以利用我计算机上的所有内核。这里有一个很好的指南:http://www.r-bloggers.com/a-brief-foray-into-parallel-processing-with-r/
【讨论】:
以上是关于在 R 中处理地理数据时提高性能的主要内容,如果未能解决你的问题,请参考以下文章