Rcpp:比较从 R 数据帧派生的字符串的简洁方法


在 Rcpp

处理字符串时有些头疼,看过"如何测试 Rcpp::CharacterVector 元素的相等性",但情况比这要复杂一些。

为了说明这一点,假设我们有一个随机生成的 200 行名称和标记数据框:

df = data.frame(name = paste("Person",
                             sample(LETTERS[1:10],200,rep=TRUE),sep=""), 
                mark = pmax(pmin(round(rnorm(200,60,15)),100),0), 
                stringsAsFactors=FALSE)

我发现以下内联代码(使用 Rcpp)正确地计算出所有行的标记总和,其中命名的人是数据框中给出的第一个人(即 R 中的 df$name[1],或等效的名称 Rcpp 代码中的 name[0]):

library(inline)
fastfunc_good1 <- cxxfunction(
    signature(DFin = "data.frame"),
    plugin = "Rcpp",
    body = '
        Rcpp::DataFrame DF(DFin);
        Rcpp::CharacterVector name = DF["name"];
        Rcpp::IntegerVector mark = DF["mark"];
        Rcpp::CharacterVector targetname(1);
        Rcpp::CharacterVector thisname(1);      
        int n = name.length();
        int tot = 0;
        targetname = name[0];
        std::string s_targetname = as<std::string>(targetname);
        for (int i = 0; i < n; i++) {
            thisname=name[i];
            std::string s_thisname = as<std::string>(thisname);
            if (s_thisname == s_targetname) {
                tot = tot + mark[i];
            }
        }
        return(Rcpp::wrap(tot));
        ')

现在,我真的想尽可能地简化这一点,因为必须定义一个单独的变量来表示 name[] 中的值,强制使用 std::string,然后进行比较是很混乱的。必须有某种简化符号的方法,使其看起来更像以下内容(应该注意的是不起作用!...

fastfunc_bad1 <- cxxfunction(
    signature(DFin = "data.frame"),
    plugin = "Rcpp",
    body = '
        Rcpp::DataFrame DF(DFin);
        Rcpp::CharacterVector name = DF["name"];
        Rcpp::IntegerVector mark = DF["mark"];
        int n = name.length();
        int tot = 0;
        for (int i = 0; i < n; i++) {
            if (name[i] == name[0]) {
                tot = tot + mark[i];
            }
        }
        return(Rcpp::wrap(tot));
        ')

这个迷你学习项目的最终目标是让我弄清楚如何遍历 df$name 中的唯一名称,计算每个名称的标记总和,并将所有内容(唯一名称和相应的总和)作为整洁的数据框返回。我已经从其他示例中弄清楚了如何构建和返回最终数据帧的大部分细节 - 只是上面描述的字符串内容让我头疼。提前非常感谢任何指示!

可以使用

Rcpp::as 将 R 对象转换为C++容器。以下内容对我有用。

fastfunc_good2 <- cxxfunction(
    signature(DFin = "data.frame"),
    plugin = "Rcpp",
    body = '
        Rcpp::DataFrame DF(DFin);
        std::vector<std::string> name = Rcpp::as<std::vector<std::string> >(DF["name"]);
        std::vector<int> mark = Rcpp::as<std::vector<int> >(DF["mark"]);
        int n = name.size();
        int tot = 0;
        for (int i = 0; i < n; i++) {
            if (name[i] == name[0]) {
                tot = tot + mark[i];
            }
        }
        return(Rcpp::wrap(tot));
        ')

> fastfunc_good1(df)
[1] 1040
> fastfunc_good2(df)
[1] 1040

最新更新