首页 文章

在R循环中动态删除元素

提问于
浏览
1

好的,根据要求,我将添加更多信息,以便您了解为什么无法进行简单的矢量操作 . 用几句话来解释并不容易,但让我们看看 . 我在2D空间有很多分数 . 我将我的空间划分为一个给定分辨率的网格,比如100米 . 我不确定它是否强制的主循环(任何替代方案都是欢迎的)是通过包含至少2个点的每个单元/像素(现在我在包spatstat中使用方法quadratcount) . 在这个循环内部,因此对于这个非空单元格中的每一个,我必须找到并保持最多10个彼此相距3米的男女对 . 可以使用spatstat中的“disc”功能完成3米缓冲区 . 要选择落在缓冲区内的点,可以使用SDMTools包中的方法pnt.in.poly . 这一切都是因为像素具有不能超过的最大容量 . 因为在每个单元格中可能有数百或数千个点我试图找到一种智能的方法来使用另一个循环/类似方法:1)一次通过每个点2)创建缓冲区一个不同性别的选择点3 )将最接近的男性 - 女性(0-1)对保存在另一个数据框中(称为new_colonies)4)从数据框中删除这些点,使其缩小,我不再需要考虑它们5)新的数据帧到达10行会停止所有内容并转到下一个单元格(从而跳过所有剩余的点 . 这是我开发的代码,用于在每个单元格中运行(现在它需要太长时间):

头(DF,20):

X       Y Sex ID
2  583058.2 2882774   1  1
3  582915.6 2883378   0  2
4  582592.8 2883297   1  3
5  582793.0 2883410   1  4
6  582925.7 2883397   1  5
7  582934.2 2883277   0  6
8  582874.7 2883336   0  7
9  583135.9 2882773   1  8
10 582955.5 2883306   1  9
11 583090.2 2883331   0 10
12 582855.3 2883358   1 11
13 582908.9 2883035   1 12
14 582608.8 2883715   0 13
15 582946.7 2883488   1 14
16 582749.8 2883062   0 15
17 582906.4 2883317   0 16
18 582598.9 2883390   0 17
19 582890.2 2883413   0 18
20 582752.8 2883361   0 19
21 582953.1 2883230   1 20

在每个细胞内,我必须根据我上面解释的内容运行 .

for(i in 1:dim(df)[1]) {

new_colonies <- data.frame(ID1=0,ID2=0,X=0,Y=0) 

discbuff <- disc(radius, centre=c(df$X[i], df$Y[i])) 

#define the points and polygon
pnts = cbind(df$X[-i],df$Y[-i])
polypnts = cbind(x = discbuff$bdry[[1]]$x, y = discbuff$bdry[[1]]$y)
out = pnt.in.poly(pnts,polypnts)
out$ID <- df$ID[-i]

if (any(out$pip == 1)) {

pnt.inBuffID <- out$ID[which(out$pip == 1)] 
cond <- df$Sex[i] != df$Sex[pnt.inBuffID]

if (any(cond)){

eucdist <- sqrt((df$X[i] - df$X[pnt.inBuffID][cond])^2 + (df$Y[i] - df$Y[pnt.inBuffID][cond])^2)

IDvect <- pnt.inBuffID[cond]
new_colonies_temp <- data.frame(ID1=df$ID[i], ID2=IDvect[which(eucdist==min(eucdist))], 
                 X=(df$X[i] + df$X[pnt.inBuffID][cond][which(eucdist==min(eucdist))]) / 2, 
                 Y=(df$Y[i] + df$Y[pnt.inBuffID][cond][which(eucdist==min(eucdist))]) / 2)

new_colonies <- rbind(new_colonies,new_colonies_temp)

if (dim(new_colonies)[1] == maxdensity) break

}
}
}

new_colonies <- new_colonies[-1,]

任何帮助赞赏!谢谢弗朗切斯科

3 回答

  • 1

    在你的情况下,我不会担心你去的时候删除积分,跳过是关键的事情 . 我也不会像你似乎正在做的那样一块一块地组成一个新的data.frame . 这两件事都让你失望很多 . 选择向量更有效(可能是data.frame的一部分,您事先设置为FALSE) .

    df$sel <- FALSE
    

    现在,当您通过时,为每个要保留的项目设置df $ sel为TRUE . 当你找到10时,只需跳到下一个单元格 . 随时删除值将耗费时间和内存密集,因为慢慢增长一个新的data.frame . 当您完成所有操作后,您只需根据选择列选择数据即可 .

    df <- df[ df$sel, ]
    

    (或者可以在那时制作data.frame的副本)

    您还可能希望使用 dist 函数来计算距离矩阵 .

    来自 ?dist

    “此函数计算并返回通过使用指定的距离度量计算的距离矩阵,以计算数据矩阵行之间的距离 . ”

  • 4

    我假设你做的事情足够复杂,实际上需要for循环......

    所以这里's one rather simple approach: first just gather the rows to delete (or keep), and then delete the rows afterwards. Typically this will be much faster too since you don' t在每次循环迭代时修改 data.frame .

    df <- generateTheDataFrame()
    
    keepRows <- rep(TRUE, nrow(df))
    for(i in seq_len(nrow(df))) {
      rows <- findRowsToDelete(df, df[i,]) 
      keepRows[rows] <- FALSE
    }
    
    # Delete afterwards
    df <- df[keepRows, ]
    

    ...如果你真的需要在每次迭代中处理收缩数据,只需将for-loop部分更改为:

    for(i in seq_len(nrow(df))) {
      if (keepRows[i]) {
          rows <- findRowsToDelete(df[keepRows, ], df[i,]) 
          keepRows[rows] <- FALSE
      }
    }
    
  • 2

    我不清楚你为什么要循环 . 如果你能描述一下你正在检查的条件,可能会有一个很好的矢量化方法 .

    但是,作为一个非常简单的修复,您是否考虑过向后循环数据帧?

相关问题