1

在 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],或等效名称[0] 在 Rcpp 代码中):

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 中的唯一名称,计算每个名称的标记总和,并将所有内容(唯一名称和相应的总和)作为一个整洁的数据框返回. 我已经从其他示例中弄清楚了如何构建和返回最终数据框的大部分细节——只是上面描述的字符串让我头疼。非常感谢您的任何指点!

4

1 回答 1

5

您可以使用 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
于 2012-06-05T09:43:08.180 回答