【问题标题】:Dynamically Delete Elements WIthin an R loop在 R 循环中动态删除元素
【发布时间】:2011-12-31 17:22:30
【问题描述】:

好的,伙计们,根据要求,我将添加更多信息,以便您了解为什么无法进行简单的矢量运算。用几句话来解释并不容易,但让我们看看。我在 2D 空间上有很多点。 我将我的空间划分为一个给定分辨率的网格,比如 100m。我不确定它是否是强制性的(欢迎任何替代方案)的主循环是遍历每个包含至少 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,]

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

【问题讨论】:

  • 欢迎来到 SO,请尝试给我们一个可重现的例子,例如通过使用dput(head(df,10))。此外,如果您了解该特定条件,那将是一件好事,因为您可能甚至不需要循环,但可以通过矢量化方式解决它。
  • 我将指定我需要对相关代码做的所有事情,只要它可以让我回答我自己的问题并在此处发布...尽快检查它,如果你能帮助我,那就太好了!
  • @Francesco - 您可以(并且应该)简单地编辑您的问题!
  • @Tommy...谢谢,我是新来的,所以我不知道我可以编辑我的帖子。
  • 您应该说明如何选择要保留的 10 个……前 10 个?、彼此最近的 10 个?、随机 10 个……等等。

标签: list r for-loop foreach dataframe


【解决方案1】:

在你的情况下,我不会担心删除点,跳过是关键。我也不会像您似乎正在做的那样逐个制作新的 data.frame 。这两件事都会让你慢很多。拥有一个选择向量会更有效(可能是您预先设置为 FALSE 的 data.frame 的一部分)。

df$sel <- FALSE

现在,当您完成时,您将要保留的每个项目的 df$sel 设置为 TRUE。当你找到你的 10 时,只需跳到下一个单元格。在你去的时候删除值将是耗时和内存密集型的,慢慢地增长一个新的 data.frame 也会如此。完成所有操作后,您可以根据选择列选择数据。

df <- df[ df$sel, ]

(或者可能在那时复制 data.frame)

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

来自?dist

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

【讨论】:

  • 我会尽快发布我的答案,并附上我想要做什么的所有解释。如果可以的话,请检查一下...谢谢
  • 非常感谢...我会尝试的。所以基本上使用 rbind 一次构建一个数据帧在 R 中是耗时且缓慢的。所以你说我无法摆脱 2 个 for 循环(一个通过每个网格单元和一个(上面的代码)遍历该单元格中的每个点....?我对这个数据帧堆栈过程还有另一个问题,但我稍后会在另一个部分中发布。
  • 最好保留外循环。您的内部循环可能大部分都可以矢量化。你看过 dist 吗?
【解决方案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 循环部分更改为:

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

【讨论】:

  • 即使您必须在行上运行循环以获取稍后检查是否要保留该行的值,最好事后进行检查。这些示例中的任何一个都将比后续矢量化选择花费更多的时间。
  • @john - 是的,但只有在可行的情况下。如果没有更多信息,这只是另一种猜测——尽管是一个很好的猜测;-)。矢量化很棒,但并非总是可行(想到条件累积和)。
【解决方案3】:

我不太清楚你为什么要循环播放。如果您可以描述您正在检查的条件类型,那么可能会有一种很好的矢量化方式。

但是,作为一个非常简单的解决方法,您是否考虑过向后循环数据框?

【讨论】:

  • 我为什么要向后循环?这样做会更快吗?
  • 如果您向后循环并在执行过程中删除行,则不一定有效,但这样您就不会跳过行。
  • 但在这种情况下我的问题是,由于循环需要索引范围,如果我在循环期间删除一些行,我会收到索引超出范围的错误(因为数据框的维度会改变)?
  • 向后循环将解决维度问题。但这一切都没有实际意义,因为如果你使用 R,你真的不应该通过使用循环来做到这一点。
猜你喜欢
  • 2020-08-25
  • 2015-05-23
  • 2020-06-02
  • 2012-02-15
  • 1970-01-01
  • 2023-03-16
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多