我有一个包含500万条记录的数据集,格式如下:
library(dplyr)
Data <- tibble(X=runif(5000000, min=200000, max=400000),
Y=runif(5000000, min=400000, max=500000),
UID = 1:5000000,
Count = runif(5000000, min=1, max=2000))
字符串
对于每个UID,我需要总结1)其他点的数量2)其他点的计数和3)200m,400m,800m和1600m范围内UID的密度计算。所需的最终输出是一个包含每个UID及其摘要输出的表。
这个for循环说明了所需的输出,但需要几周才能完成:
Summary <- NULL
for (n in 1:nrow(Data)){
Data_Row <- Data[n,]
Row_200 <- Data %>% filter(between(X, Data_Row$X-200,Data_Row$X+200) & between(Y, Data_Row$Y-200, Data_Row$Y+200)) %>%
summarise(Instances_200 = n(), Count_200 = sum(Count), Calcualtion_200 = Count_200/(Instances_200*0.000625))
Row_400 <- Data %>% filter(between(X, Data_Row$X-400,Data_Row$X+400) & between(Y, Data_Row$Y-400, Data_Row$Y+400)) %>%
summarise(Instances_400 = n(), Count_400 = sum(Count), Calcualtion_400 = Count_400/(Instances_400*0.000625))
Row_800 <- Data %>% filter(between(X, Data_Row$X-800,Data_Row$X+800) & between(Y, Data_Row$Y-800, Data_Row$Y+800)) %>%
summarise(Instances_800 = n(), Count_800 = sum(Count), Calcualtion_800 = Count_800/(Instances_800*0.000625))
Row_1600 <- Data %>% filter(between(X, Data_Row$X-1600,Data_Row$X+1600) & between(Y, Data_Row$Y-1600, Data_Row$Y+1600)) %>%
summarise(Instances_1600 = n(), Count_1600 = sum(Count), Calcualtion_1600 = Count_1600/(Instances_1600*0.000625))
Summary_Row <- bind_cols(Data[n,"UID"], Row_200, Row_400, Row_800, Row_1600)
Summary <- bind_rows(Summary, Summary_Row)
}
型
我知道像lapply
和map
这样的东西,但我不知道如何使用它们来更快地进行动态过滤和汇总。
4条答案
按热度按时间ttisahbt1#
基于@Jon Spring的评论,我用这个答案作为灵感来加快这个过程。下面的答案现在需要大约12个小时来运行我的真实的数据(而不是我的问题中的代码需要几天/几周)。这是一个有点内存饥饿的点(我使用的是Windows桌面与32 GB的RAM),这就是为什么我已经尽量减少什么得到存储(iidoEe。为什么我把每个循环的输出写到CSV,然后在最后把它们带回来)。使用
data.table
确实加快了速度,但我相信仍然会有一种更快/更有效的方法来做到这一点-但这正是我所需要的(即使我的代码很混乱!).字符串
**编辑:**添加了set.seed(),并稍微改变了循环的开始,因此只有相关的列与'crossing'一起使用(这对我来说是内存效率)。
输出
第一环的前五行:
| 示例_200|计数_200|计算_200|示例_400|计数_400|计算_400|示例_800|计数_800|计算_800|示例_1600|计数_1600|计算_1600| Calculation_1600 |
| --|--|--|--|--|--|--|--|--|--|--|--| ------------ |
| 二十|二十四|四点八|八十八|一百一十九|5.40909090909| 360度|四七五|5.2777777777777|一五零三|2041| 5.43180306054557| 5.43180306054557 |
| 二十二|二十八|5.090909090909|八十七|一百一十九|5.47126436781609| 360度|四七五|5.2777777777777|一千五|2049| 5.464| 5.464 |
| 二十|三十|六|86|一百一十七|5.44186046511627|三六四|四七九|5.26373626373626|一四九四|二〇三二|5.44042838018741| 5.44042838018741 |
| 二十一|三十|5.71428571428571|八十五|一百一十三|5.31764705882352|三六四|四七九|5.26373626373626|一四九一|二〇三七|5.46478873239436| 5.46478873239436 |
| 二十八|四十二|六|八十五|一百一十三|5.31764705882352|三百六十九|四八五|5.25745257452574|一四八七|二〇二〇年|5.43375924680564| 5.43375924680564 |
mklgxw1f2#
我试图理解OP的回答帖子,特别是输出表。
关注输出表的第一行--我看到
SC550650NE
被报告为在(X=255085.6, Y=465070.1)
的200个范围内有另一个点的20个示例,总和计数为24。字符串
所以我计算所有点相对于
(X=255085.6, Y=465070.1)
的距离。然后按升序显示200以内的。我数了29,不是20。另外,当我计算总数时,我得到25,463,而不是24。型
编辑
500万行
因此,在不明智地使用评论进行讨论(对不起,所以!我们对自己的处境有了更好的认识。@Chris有一个解决方案,给出了一个近似值,但这是为了降低计算时间而做出的让步。在讨论过程中,我们还了解到距离度量可以是正方形或圆形,并且机器上有4个核心可用。
我将提出两个解决方案,一个是圆度量,一个是平方度量。圆度量更快。
两者都遵循this SO post中的方法。
圆度量
distance = sqrt( (x1-x2)^2 + (y1-y2)^2) ) <= 200
型
选择
num.rows
中的一个。从小处着手,逐步掌握时机。我也有32 GB(在Mac上),所以我希望它是可比的。粗略地看,行数增加一倍导致计算时间增加4倍。型
此方法依赖于传递数据集的整个X、Y和Count列。我们分别将它们记为
Xvec
、Yvec
和Cvec
。从那里我们创建了一个函数instances()
,它将首先计算1个点(x.in, y.in)
到(Xvec
,Yvec
)中所有其他点的距离,计算示例并执行sumCount(密度“计算”在最后完成,不需要在此步骤中完成或并行化)。这个函数
instances()
被部署在一个data.table中,并在函数instances.stacked()
中进行了设置。由于我们传递了数据集的整个X、Y和Count列,并在原始数据集中按行操作,因此我们可以并行处理这个问题。如果我们有500万个parallel::detectCores()
,那么每行就有一个核心,并且可以在瞬间完成。然而,我们有4个,所以我们花了一点时间来创建一个变量group_quarters
,它将通过foo2()
对split_df()
的部署将数据集分成4个块(这两个都改编自上述SO post中的示例)。对foo 2()的调用将并行部署分析,并将所有内容组合回
results_wide
。然后我们可以进行密度计算并查看一些结果。它给出(42 1/2小时后):
平方度量
(X-200, X+200) & (Y-200, Y+200)
...注意...我重载了一些函数名,因此最好将此代码放在单独的脚本中,并将R会话与圆度量代码分开
类似于上面的
circle metric
方法,但执行略有不同,因为它是基于边界而不是距离。基本上,我们制作一个数据的超级堆栈,并计算每个距离的特定边界。这四个“边界”是对数据进行分块以进行并行化的自然候选者--这段代码更进一步,将这四个“边界”中的每一个分成两半,得到8个组。但我们仍然在4个节点上运行。我在8个节点上测试了一堆,因为我的测试环境允许这样做,在我知道OP有4个核心环境之前,我开发了这个代码。创建一个超级堆栈:
我包括了这个注解块--这是在不并行化的情况下运行它的方法。继续,现在跳到下一个块。
下面是并行代码。我分成了8个组,但将makeCluster行更改为4个节点。
toiithl63#
作为一个说一定有人能比我做得更好的人,我会寻找别人提出的解决方案。
因此,我看到了使用
sf
和spdep
包的一些优势。两者都是为空间数据而设计的。首先有两个功能。
创建一个sf-object
字符串
距离可以用
型
当然,必须找到一个不计算所有距离的解决方案。一个简单的算法是将点分类到所需半径一半大小的箱中。然后,您只需检查相邻垃圾箱中的点。
ecfsfe2w4#
使用data.table可能会有所帮助。但就这宗个案而言,我认为计算时间仍会太长。
可能是你无论如何都要试试:
字符串
诸如此类。