interpolation/lookup 在 R 中

interpolation/lookup in R

我正在从 excel 切换到 R,并且想知道如何在 R 中执行此操作。
我有一个看起来像这样的数据集:

df1<-data.frame(Zipcode=c("7941AH","7941AG","7941AH","7941AZ"),
                From=c(2,30,45,1),
                To=c(20,38,57,8),
                Type=c("even","mixed","odd","mixed"),
                GPS=c(12345,54321,11221,22331)) 

df2<-data.frame(zipcode=c("7914AH", "7914AH", "7914AH", "7914AG","7914AG","7914AZ"), 
                housenum=c(18, 19, 50, 32, 104,11))

第一个数据集包含邮政编码、门牌号范围(从和到)、类型含义(如果范围包含偶数、奇数或混合门牌号)和 gps 坐标。第二个数据集仅包含地址(邮政编码、门牌号)。

我想做的是查找 df2 的 gps 坐标。例如,邮政编码 7941AG 和门牌号 18(2 到 20 之间的偶数)的地址具有 gps 坐标 12345.

更新: 因为我没有想到数据集的大小对于所选解决方案很重要(我知道,有点天真......)这里有一些额外的信息: df1 的实际大小是 472.000 个观察值,而 df2 有 110 万个观察值。 df1 中唯一邮政编码的数量为 280.000。我偶然发现了这个 post speed up the loop operation in R 有一些有趣的发现,但我不知道如何将其合并到@josilber

提供的解决方案中

我将循环遍历 df2 中的每个元素,实现检查邮政编码是否匹配以及元素范围是否正确以及 even/odd 是否正确所需的逻辑:

# Clean up data (character zip codes and fix the 7914 vs. 7941 issue in zip codes)
df2<-data.frame(zipcode=c("7941AH", "7941AH", "7941AH", "7941AG","7941AG","7941AZ"), 
                housenum=c(18, 19, 50, 32, 104,11))
df1$Zipcode <- as.character(df1$Zipcode)
df2$zipcode <- as.character(df2$zipcode)

# Loop to compute the GPS values
sapply(seq(nrow(df2)), function(x) {
  m <- df2[x,]
  matched <- df1$Zipcode == m$zipcode &
    m$housenum >= df1$From &
    m$housenum <= df1$To &
    (df1$Type == "mixed" |
     (df1$Type == "odd" & m$housenum %% 2 == 1) |
     (df1$Type == "even" & m$housenum %% 2 == 0))
  if (sum(matched) != 1) {
    return(NA)  # No matches or multiple matches
  } else {
    return(df1$GPS[matched])
  }
})
# [1] 12345    NA    NA 54321    NA    NA

通过检查,只有 df2 的第一个和第四个元素符合 df1 中的一个规则。

给定大数据框,你最好的选择可能是通过它们的邮政编码合并 df1df2(也就是从具有相同邮政编码的数据框中获取每一对行),按门牌号条件过滤,去除重复项(df1中的多个规则匹配的情况),然后存储所有匹配房屋的信息。让我们从您指定大小的示例数据集开始:

set.seed(144)
df1 <- data.frame(Zipcode=sample(1:280000, 472000, replace=TRUE),
                  From=sample(1:50, 472000, replace=TRUE),
                  To=sample(51:100, 472000, replace=TRUE),
                  Type=sample(c("even", "odd", "mixed"), 472000, replace=TRUE),
                  GPS=sample(1:100, 472000, replace=TRUE))
df2 <- data.frame(zipcode=sample(1:280000, 1.1e6, replace=TRUE),
                  housenum=sample(1:100, 1.1e6, replace=TRUE))

现在我们可以对 GPS 数据进行高效计算了:

get.gps <- function(df1, df2) {
  # Add ID to df2
  df2$id <- 1:nrow(df2)
  m <- merge(df1, df2, by.x="Zipcode", by.y="zipcode")
  m <- m[m$housenum >= m$From &
         m$housenum <= m$To &
         (m$Type == "mixed" |
          (m$Type == "odd" & m$housenum %% 2 == 1) |
          (m$Type == "even" & m$housenum %% 2 == 0)),]
  m <- m[!duplicated(m$id) & !duplicated(m$id, fromLast=TRUE),]
  GPS <- rep(NA, nrow(df2))
  GPS[m$id] <- m$GPS
  return(GPS)
}
system.time(get.gps(df1, df2))
#    user  system elapsed 
#  16.197   0.561  17.583 

这是一个更可接受的运行时间 -- 18 秒,而不是您在我的其他答案的评论中估计的 90 小时!