【问题标题】:Simple lookup to insert values in an R data frame在 R 数据框中插入值的简单查找
【发布时间】:2013-07-24 20:24:36
【问题描述】:

这是一个看似简单的 R 问题,但我在这里没有看到确切的答案。我有一个如下所示的数据框(alldata):

Case     zip     market
1        44485   NA
2        44488   NA
3        43210   NA

有超过 350 万条记录。

然后,我有第二个数据框,“邮政编码”。

market    zip
1         44485
1         44486
1         44488
...       ... (100 zips in market 1)
2         43210
2         43211
...       ... (100 zips in market 2, etc.)

我想根据 alldata$zip 匹配邮政编码数据框中的适当值,为每个案例找到正确的 alldata$market 值。我只是在寻找正确的语法,像往常一样非常感谢您的帮助。

【问题讨论】:

  • 您正在寻找merge。搜索所以[r] merge,你会找到它
  • @Ricardo Saporta on 3.5 merge 可能有点慢。
  • @TylerRinker,我经常在 4 亿行上使用 merge.data.table,而且速度非常快。不过使用qdap 很好
  • 哦,哇,从来没有处理过这么大的数据。感谢经验丰富的回复。

标签: r lookup-tables


【解决方案1】:

由于您不关心alldata 中的market 列,您可以首先使用mergealldatazipcodes 中的列合并到zip 列中:

merge(alldata[, c("Case", "zip")], zipcodes, by="zip")

by 参数指定键条件,因此如果您有复合键,则可以执行by=c("zip", "otherfield") 之类的操作。

【讨论】:

  • 这不会为所有数据中没有的邮政编码引入 NA 吗?
  • @Rodrigo 默认情况下,您只会在两个数据框中获得匹配的行。这可以通过allall.xall.y 选项进行控制
【解决方案2】:

另一个对我有用且非常简单的选项:

alldata$market<-with(zipcodes, market[match(alldata$zip, zip)])

【讨论】:

  • 如此简单却又如此棒!
  • 如果你能解释那里发生了什么就太好了。
  • 来自 R 文档:“match 在第二个参数中返回其第一个参数的(第一个)匹配位置的向量”。所以基本上match 返回一个正确索引的向量来访问 zipcodes$market 以获得 alldata$market 的正确市场价值。
【解决方案3】:

对于如此庞大的数据集,您可能需要环境查找的速度。您可以使用qdapTools package 中的lookup 函数,如下所示:

library(qdapTools)
alldata$market <- lookup(alldata$zip, zipcodes[, 2:1])

或者

alldata$zip %l% zipcodes[, 2:1]

【讨论】:

  • Tyler,我在更大的数据上对此进行了测试,lookup(.) 的步骤被证明很耗时(我在一段时间后停止了它)。我把它作为gist。我做对了吗?通过快速调试,耗时部分似乎是 sapply(.) 内部 recoder 函数。
  • @Arun 感谢您的要点。根据您的发现,我在 dev version 中添加了一些改进,这些改进显着提高了速度。
  • 只是出于好奇,您是否将data.table 放在板凳上以查看它的比较情况。我已阅读 data.table 在查找方面做出了一些不错的改进,包括字符查找。
  • 我用两种方式编辑了要点。 1) 一个连接(虽然这里真的不需要)和 2) 使用 match:=,虽然对大量数据进行基准测试会更好。 HTH。
  • 是的,从 1.9.0+ 开始有很多令人欢迎的变化。这应该是令人信服的:require(data.table); set.seed(1L); x = sample(paste0("V", 1:1e6)); system.time(ans1 &lt;- data.table:::forderv(x)); system.time(ans2 &lt;- order(x)); identical(ans1, ans2).
【解决方案4】:

这是dplyr 的做法:

library(tidyverse)
alldata %>%
  select(-market) %>%
  left_join(zipcodes, by="zip")

在我的机器上,它的性能与lookup 大致相同。

【讨论】:

    【解决方案5】:

    match 的语法有点笨拙。您可能会发现lookup 包更易于使用。

    alldata <- data.frame(Case=1:3, zip=c(44485,44488,43210), market=c(NA,NA,NA))
    zipcodes <- data.frame(market=c(1,1,1,2,2), zip=c(44485,44486,44488,43210,43211))
    alldata$market <- lookup(alldata$zip, zipcodes$zip, zipcodes$market)
    alldata
    ##   Case   zip market
    ## 1    1 44485      1
    ## 2    2 44488      1
    ## 3    3 43210      2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      相关资源
      最近更新 更多