用R循环动态删除元素

时间:2011-11-17 20:46:41

标签: list r for-loop foreach dataframe

好的,按照要求,我会添加更多信息,以便您了解为什么无法进行简单的矢量操作。用几句话来解释并不容易,但让我们看看。我在2D空间有很多分数。 我将我的空间划分为一个给定分辨率的网格,比如100米。我不确定它是否强制的主循环(任何替代方案都是欢迎的)是通过包含至少2个点的每个单元/像素(现在我在包spatstat中使用方法quadratcount)。 在这个循环内部,因此对于这个非空单元格中的每一个,我必须找到并保持最多10个彼此相距3米的男女对。 3米缓冲区可以使用spatstat中的“disc”功能完成。要选择落在缓冲区内的点,可以使用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 个答案:

答案 0 :(得分:4)

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

df$sel <- FALSE

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

df <- df[ df$sel, ]

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

您可能还想使用dist函数来计算距离矩阵。

来自?dist

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

答案 1 :(得分:2)

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

所以这是一个相当简单的方法:首先收集要删除(或保留)的行,然后删除行。通常这会更快,因为您不会在每次循环迭代时修改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 :(得分:1)

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

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