【问题标题】:How to count the number of non-empty fields in a delimited file?如何计算分隔文件中非空字段的数量?
【发布时间】:2015-12-17 01:53:20
【问题描述】:

您可以使用utils::count.fields 计算逗号/制表符/任何分隔的文本文件中每行的字段数。

这是一个可重现的例子:

d <- data.frame(
  x = c(1, NA, 3, NA, 5),
  y = c(NA, "b", "c", NA, NA),
  z = c(NA, "beta", "gamma", NA, "epsilon")
)

fname <- "test.csv"
write.csv(d, fname, na = "",  row.names = FALSE)
count.fields(fname, sep = ",")
## [1] 3 3 3 3 3 3

我想计算每行的非空字段数。我可以通过读取所有内容并计算不是NA 的值的数量来以笨拙的方式做到这一点。

d2 <- read.csv(fname, na.strings = "")
rowSums(!is.na(d2))
## [1] 1 2 3 0 2

我真的很想要一种扫描文件的方式(例如count.fields),这样我就可以针对特定的部分进行读取。

有没有更好的方法来计算分隔文件中非空字段的数量?

【问题讨论】:

    标签: r csv import


    【解决方案1】:

    如果您安装了 RcppBH 软件包,这应该是完全可移植的:

    library(Rcpp)
    library(inline)
    
    csvblanks <- '
    string data = as<string>(filename);
    ifstream fil(data.c_str());
    if (!fil.is_open()) return(R_NilValue);
    
    typedef tokenizer< escaped_list_separator<char> > Tokenizer;
    
    vector<string> fields;
    vector<int> retval;
    string line;
    
    while (getline(fil, line)) {
      int numblanks = 0;
      Tokenizer tok(line);
      for(Tokenizer::iterator beg=tok.begin(); beg!=tok.end(); ++beg){
        numblanks += (beg->length() == 0) ? 1 : 0 ;
      };
      retval.push_back(numblanks);
    }
    return(wrap(retval));
    '
    
    count_blanks <- rcpp(
      signature(filename="character"),
      body=csvblanks,
      includes=c("#include <iostream>",
                 "#include <fstream>",
                 "#include <vector>",
                 "#include <string>",
                 "#include <algorithm>",
                 "#include <iterator>",
                 "#include <boost/tokenizer.hpp>",
                 "using namespace Rcpp;",
                 "using namespace std;",
                 "using namespace boost;")
    )
    

    获取该信息后,您可以调用count_blanks(FULLPATH),它将返回每行空白字段计数的数字向量。

    我针对这个文件运行了它:

    "DATE","APIKEY","FILENAME","LANGUAGE","JOBID","TRANSCRIPT"
    1,2,3,4,5
    1,,3,4,5
    1,2,3,4,5
    1,2,,4,5
    1,2,3,4,5
    1,2,3,,5
    1,2,3,4,5
    1,2,3,4,
    1,2,3,4,5
    1,,3,,5
    1,2,3,4,5
    ,2,,4,
    1,2,3,4,5
    

    通过:

    count_blanks("/tmp/a.csv")
    ## [1] 0 0 1 0 1 0 1 0 1 0 2 0 3 0
    

    注意事项

    • 很明显,它没有忽略标头,因此它可以使用带有关联 C/C++ 代码的 header 逻辑参数(这将非常简单)。
    • 如果您将“空格”(即[:space:]+)算作“空”,则需要比调用length 更复杂的内容。如果需要,This 是一种潜在的处理方式。
    • 它使用定义为here 的Boost 函数escaped_list_separator 的默认配置。这也可以使用引号和分隔符进行自定义(可以进一步模仿read.csv/read.table

    这将更接近count.fields/C_countfields 的性能,并且无需通过读取每一行来查找您最终想要更优化定位的行来消耗内存。我不认为为返回的数字向量预分配空间会大大提高速度,但您可以查看讨论 here,其中显示了如果需要如何执行此操作。

    【讨论】:

    • 我刚刚意识到你想计算 non-empty,我希望它的反面是微不足道的,不需要编辑;-)
    猜你喜欢
    • 2012-01-31
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多