英文:
Develop a custom Rcpp function to be used with terra::focalCpp to calculate the percent of a specific value within a moving window
问题
以下是您要翻译的内容:
我正在尝试使用terra::focal来加速一些栅格处理,通过使用focalCpp来实现。
这里有一些示例数据,其中包含了1和NAs,以复制实际数据集
```R
nr <- nc <- 50
r <- rast(ncols=nc, nrows=nr, ext= c(0, nc, 0, nr))
values(r) <- rep(c(rep(NA, 10), rep(1, 10), seq(1,8), rep(1,12), rep(NA,5), rep(1,15),seq(1,8), rep(NA,12), seq(1,20)), 50)
这是我尝试在Rcpp中复制的原始用于focal的函数:
fxnpercent = function(x) {
q=x # 复制x
q[q!=1] = NA # q变为1
length(q[!is.na(q)])/length(x[!is.na(x)]) * 100 # 获取1的百分比
}
这是原始focal函数,窗口通过200米缓冲区来近似:
# 移动窗口矩阵
mat = matrix(1,15,15) # 创建一个包围缓冲区范围的1矩阵
gr = expand.grid(1:nrow(mat), 1:nrow(mat)) # 基于行/列索引的所有成对值的数据框
center = 8 # 方形网格的中心索引
gr$dist = sqrt((gr$Var1-center)^2 + (gr$Var2-center)^2) # 欧几里德距离计算
threshold = 200/30 # 200米阈值转换为像素数(从中心计算)
gr$inside = ifelse(gr$dist < threshold, 1, NA) # 如果距离小于阈值,则网格值为1,否则为NA
w = matrix(gr$inside, 15,15) # 使用gr$inside,将索引值放入原始维度的矩阵中
# 输出移动窗口的百分比
percent = terra::focal(x=r, w=w, fun=fxnpercent, na.policy="all")
这是我尝试在Rcpp中复制fxnpercent函数的代码:
cppFunction(
'NumericVector fxnpercent(NumericVector x, size_t ni, size_t nw) {
NumericVector out(ni);
// 循环处理单元格
size_t start = 0;
for (size_t i=0; i<ni; i++) {
size_t end = start + nw;
// 计算窗口内的值
double v = 0;
// 循环处理窗口内的值
for (size_t j=start; j<end; j++) {
if (x[j] != 1) {
v += std::nan("");
}
else {
v += x[j];
}
}
NumericVector x1 = x[!is_na(x)];
NumericVector v1 = v;
NumericVector v2 = v1[!is_nan(x)];
size_t v2size = v2.size();
size_t x1size = x1.size();
out[i] = (v2size / x1size) * 100;
start = end;
}
return out;
}'
)
在对Rcpp的语法进行了大量故障排除以确保正确性之后,我尝试使用focalCpp运行此函数,但出现错误。
percent = focalCpp(r, w=w, fun=fxnpercent, na.policy="all")
# 我当前的错误
Error: [focalCpp] 测试失败
我认为我需要在Rcpp函数的窗口循环内进行一些计算,但我在如何设置它以正常工作方面遇到了问题。
英文:
I'm trying to speed up some raster processing I'm doing using terra::focal by using focalCpp.
Here is some example data with 1s and NAs included to replicate an actual dataset
nr <- nc <- 50
r <- rast(ncols=nc, nrows=nr, ext= c(0, nc, 0, nr))
values(r) <- rep(c(rep(NA, 10), rep(1, 10), seq(1,8), rep(1,12), rep(NA,5), rep(1,15),seq(1,8), rep(NA,12), seq(1,20)), 50)
This is the original function used with focal that I'm trying to duplicate in Rcpp
fxnpercent = function(x) {
q=x # make a copy of x
q[q!=1] = NA # q becomes just 1s
length(q[!is.na(q)])/length(x[!is.na(x)]) * 100 # gets percentage of 1s
}
This is the original focal function with a window approximated by a 200m buffer
# moving window matrix
mat = matrix(1,15,15) # create matrix of 1's that envelopes the extent of the buffer
gr = expand.grid(1:nrow(mat), 1:nrow(mat)) # df of all pairwise values based on row/col index
center = 8 # centroid index of the square grid
gr$dist = sqrt((gr$Var1-center)^2 + (gr$Var2-center)^2) # euclidean distance calucation
threshold = 200/30 # 200m threshold is converted into number of pixels from center
gr$inside = ifelse(gr$dist < threshold, 1, NA) # if distance is less than threshold, grid value is one, otherwise NA
w = matrix(gr$inside, 15,15) # Using gr$inside, place indexed values into matrix of original dimensions
#output percent from moving window
percent = terra::focal(x=r, w=w, fun=fxnpercent, na.policy="all")
And this is my attempt to duplicate the fxnpercent function in Rcpp
cppFunction(
'NumericVector fxnpercent(NumericVector x, size_t ni, size_t nw) {
NumericVector out(ni);
// loop over cells
size_t start = 0;
for (size_t i=0; i<ni; i++) {
size_t end = start + nw;
// compute something for a window
double v = 0;
// loop over the values of a window
for (size_t j=start; j<end; j++) {
if (x[j] != 1) {
v += std::nan("");
}
else {
v += x[j];
}
}
NumericVector x1 = x[!is_na(x)];
NumericVector v1 = v;
NumericVector v2 = v1[!is_nan(x)];
size_t v2size = v2.size();
size_t x1size = x1.size();
out[i] = (v2size / x1size) * 100;
start = end;
}
return out;
}'
)
After lots of troubleshooting to get the syntax correct in Rcpp, I try to run this function with focalCpp and I have an error.
percent = focalCpp(r, w=w, fun=fxnpercent, na.policy="all")
#my current error
Error: [focalCpp] test failed
I think I need to do some calculations within the window loop in the Rcpp function but I'm having trouble with understanding how to set it up to work correctly.
答案1
得分: 1
NaN检查不是通过is_nan()来完成的,而是使用std::isnan()
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector fxnpercent(NumericVector x, size_t ni, size_t nw) {
NumericVector out(ni);
// 循环遍历单元格
size_t start = 0;
for (size_t i = 0; i < ni; i++) {
size_t end = start + nw;
// 计算窗口内的某些内容
double v = 0;
double totalCount = 0;
double countOfOnes = 0;
// 循环遍历窗口内的值
for (size_t j = start; j < end; j++) {
if (!std::isnan(x[j])) {
totalCount++;
if (x[j] == 1) {
countOfOnes++;
}
}
}
if (totalCount > 0) {
out[i] = (countOfOnes / totalCount) * 100;
} else {
out[i] = std::nan(""); // 如果全部都是NaN,则为NaN
}
start = end;
}
return out;
}
英文:
NaN checking is not done via is_nan() but rather using std::isnan()
#include<Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector fxnpercent(NumericVector x, size_t ni, size_t nw) {
NumericVector out(ni);
// loop over cells
size_t start = 0;
for (size_t i=0; i<ni; i++) {
size_t end = start + nw;
// compute something for a window
double v = 0;
double totalCount = 0;
double countOfOnes = 0;
// loop over the values of a window
for (size_t j=start; j<end; j++) {
if (!std::isnan(x[j])) {
totalCount++;
if (x[j] == 1) {
countOfOnes++;
}
}
}
if (totalCount > 0) {
out[i] = (countOfOnes / totalCount) * 100;
} else {
out[i] = std::nan(""); // it is NaN if all are NaN
}
start = end;
}
return out;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论