I have a data.frame A with +100 000 rows containing location information (Lat = latitude, Lon = longitude) and another data.frame B with +500 rows containing limits for geographical areas (areas do not overlap).
How can I make a function that returns a place name from B based on the locations in A?
I would like R to return a vector of place names when a location exists in B, "not assigned" in cases when a location does not exist and NA in cases when either Lat or Lon is missing in A
Example:
dataA <- structure(list(Lat = c(60L, 63L, 0L, 75L, NA, 71L, 70L), Lon = c(-70L,
-66L, 5L, -100L, 80L, -61L, -150L)), .Names = c("Lat", "Lon"), class = "data.frame", row.names = c(NA,
-7L))
dataB <- structure(list(Region = structure(c(2L, 3L, 1L), .Label = c("Beaufort Sea",
"Hudson Strait", "North West Passage"), class = "factor"), Lat.min = c(55,
70, 69.5), Lat.max = c(65L, 80L, 72L), Lon.min = c(-75L, -120L,
-160L), Lon.max = c(-60L, -60L, -120L)), .Names = c("Region",
"Lat.min", "Lat.max", "Lon.min", "Lon.max"), class = "data.frame", row.names = c(NA,
-3L))
## I would like to test for each row in dataA:
i <- 1 ## i <- 1:nrow(dataB)
dataA$Lat > dataB$Lat.min[i] & dataA$Lat < dataB$Lat.max[i] &
dataA$Lon > dataB$Lon.min[i] & dataA$Lon < dataB$Lon.max[i]
## and return
dataB$Region[i] ## only once for each row of dataA,
##unless is.na(dataA$Lat) | is.na(dataA$Lon), then return(NA),
##and if a row in dataA does not match any row in dataB, then return "not assigned"
## The result should look something like:
c("Hudson Strait", "Hudson Strait", "not assigned", "North West Passage",
NA, "North West Passage", "Beaufort Sea")
What have I tried: I have solved similar challenges using the ifelse
function previously, but in this case my conditional data.frame is far too large to do this manually. I also tried to split
data.frame A and run a conditional for
loop, but did not manage to figure out how to formulate the for loop. If I use an if
statement inside the loop, my loop returns as many values as there are rows in B values for each row in A. I also have a feeling that running a for loop for this dataset would take a long time, not to mention the size of the splitted data.frame A. There must a better way of doing this...
Here is one, certainly not the most elegant, way of doing it:
z <- lapply(1:nrow(dataB), function(i){
ifelse(is.na(dataA$Lat) | is.na(dataA$Lon), "Missing",
ifelse(dataA$Lat > dataB$Lat.min[i] & dataA$Lat < dataB$Lat.max[i] &
dataA$Lon > dataB$Lon.min[i] & dataA$Lon < dataB$Lon.max[i],
as.character(dataB$Region[i]), NA))
})
z <- do.call(rbind,z)
apply(z, 2, function(j) {
out <-j[!is.na(j)]
if(length(out) == nrow(z)) {
return(NA)} else {
if(length(out) > 0) {
return(out)} else {
return("Not assigned")
}}
})
# [1] "Hudson Strait" "Hudson Strait" "Not assigned" "North West Passage"
# NA "North West Passage" "Beaufort Sea"
Maybe someone has a more elegant solution?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.