【问题标题】:Change value conditionally (2 conditions) in a data frame and avoid loops in R在数据框中有条件地更改值(2个条件)并避免R中的循环
【发布时间】:2015-09-24 05:41:02
【问题描述】:

我有一种情况,我目前使用非常耗时的循环。

我的数据集: SPECIE(3列data.frame); WORLD(3 列矩阵)

SPECIE 中,我有 3 个变量:LAT、LON、OCC(数字) OCC 始终 > 0。SPECIE 包含找到该物种的位置,以及找到它的次数(在 OCC 中)。 SPECIE的长度通常在3000左右。

在 WORLD 中,我拥有世界上所有的经纬度(网格 -180 到 180,-90 到 90,res 0.5) 所以,在WORLD,我有:LAT、LON、OCC OCC 通常为 0。WORLD 的长度为 259200 (180 * 2 * 360 * 2) x 3columns

我的目标:在发现该物种的世界中修改 OCC。最后,我得到了世界上所有的纬度/经度,以及是否在精确的纬度/经度对中找到了该物种的信息。

目前,我这样做:

for(j in 1:259200)
{
for(k in 1:length(SPECIE$OCC))
{

if((SPECIE$LON[k] == WORLD[j,1]) & (SPECIE$LAT[k] == WORLD[j,2]))
{
WORLD[j,3] <- SPECIE$OCC[k]
}

}
}

我寻找了一个没有循环的解决方案(这需要几个小时),但没有找到可行的方法。

头:

> head(WORLD)
    [,1]      [,2]   [,3]
[1,] -179.75 -89.75    0
[2,] -179.75 -89.25    0
[3,] -179.75 -88.75    0
[4,] -179.75 -88.25    0

> head(SPECIE)
    LON   LAT     OCC
1 -89.75 24.75       1
2 -89.75 25.25       1
3 -89.75 25.75       6
4 -89.75 26.25      45

非常感谢!

【问题讨论】:

    标签: r replace dataframe data.table conditional-statements


    【解决方案1】:

    神奇的data.table 包是你的朋友,它会在眨眼间完成这项工作。

    由于您没有提供数据,我模拟了一些,使得 SPECIE 中的 LAT 和 LON 的所有值都包含在 WORLD 中的相同坐标内,但也有 WORLD 中不包含在 SPECIE 中的值。我为 LAT 和 LON 制定了非常常规的值,但对于真实数据,它应该以相同的方式工作。

    require(data.table)
    
    # set lengths for example
    nSPECIE <- 5
    nWORLD <- 10
    
    # simulate the SPECIE data, from data.frame to data.table
    SPECIE <- data.frame(LAT = 1:nSPECIE,
                         LON = 1:nSPECIE,
                         OCC_specie = 1:nSPECIE)
    SPECIE <- as.data.table(SPECIE)
    
    # simulate the WORLD data, from matrix to data.table
    WORLD <- matrix(c(1:nWORLD,
                      1:nWORLD,
                      rpois(nWORLD, 1)),
                    ncol = 3,
                    dimnames = list(NULL, c("LAT", "LON", "OCC_world")))
    WORLD <- as.data.table(WORLD)
    
    # merge
    setkey(SPECIE, LAT, LON)
    setkey(WORLD, LAT, LON)
    WORLD_modified <- SPECIE[WORLD]
    ##     LAT LON OCC_specie OCC_world
    ##  1:   1   1          1         0
    ##  2:   2   2          2         2
    ##  3:   3   3          3         2
    ##  4:   4   4          4         0
    ##  5:   5   5          5         0
    ##  6:   6   6         NA         1
    ##  7:   7   7         NA         0
    ##  8:   8   8         NA         2
    ##  9:   9   9         NA         2
    ## 10:  10  10         NA         3
    

    如您所见,现在匹配来自 SPECIE 的 OCC 值,并且为 WORLD 中在 SPECIE 中没有相应记录的位置赋予了来自 SPECIE 的 OCC 列的 NA 值。

    只是为了向您展示快得离谱,您可以设置参数:

    # with original sizes
    nSPECIE <- 3000
    nWORLD <- 259000
    SPECIE <- data.frame(LAT = 1:nSPECIE,
                         LON = 1:nSPECIE,
                         OCC_specie = 1:nSPECIE)
    SPECIE <- as.data.table(SPECIE)
    WORLD <- matrix(c(1:nWORLD,
                      1:nWORLD,
                      rpois(nWORLD, 1)),
                    ncol = 3,
                    dimnames = list(NULL, c("LAT", "LON", "OCC_world")))
    WORLD <- as.data.table(WORLD)
    setkey(SPECIE, LAT, LON)
    setkey(WORLD, LAT, LON)
    system.time(WORLD_modified <- SPECIE[WORLD])
    ##    user  system elapsed 
    ##   0.003   0.000   0.004
    

    阅读data.tablevignettemanual,如果您需要匹配表格,时间非常值得。优秀的 dplyr 包也使用了这个,但我更喜欢直接使用 data.table 来完成这样的工作。

    【讨论】:

      【解决方案2】:

      如果您发布一些示例数据会有所帮助,但试试这个:

      world.df <- as.data.frame(world)
      names(world) <- names(specie)
      matches <- which(world.df$lat %in% specie$lat & world.df$lon %in% specie$lon)
      world.df$occ[matches] <- merge(specie, world.df, by=c('lat', 'lon'))$occ.x
      

      【讨论】:

      • 谢谢!我编辑了我的帖子以添加示例数据。我仍然对您的解决方案有疑问,它不起作用。我有length(SPECIE$OCC) = 9434 和length(matches) = 19488,这不可能(它们在逻辑上必须相等)
      • 您可能需要切换 %in% 运算符周围的顺序。
      猜你喜欢
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 2013-07-13
      • 2022-11-25
      • 2020-01-19
      • 2021-12-03
      • 2020-07-08
      相关资源
      最近更新 更多