2015-07-10 200 views
6

我知道这个问题已在几个地方提出,我一直在试图找出一个可能的好几个小时的解决方案,但失败了。这就是我问这个的原因。data.table :: fread的stringsAsFactors = TRUE参数不会将字符列转换为因子类型 - 解决方法是什么?

所以,我有一个庞大的数据文件(〜5GB),我用fread()阅读本

library(data.table) 
df<- fread('output.txt', sep = "|", stringsAsFactors = TRUE) 
head(df, 5) 
     age   income homeowner_status_desc marital_status_cd gender 
1:   $35,000 - $49,999            
2: 35 - 44 $35,000 - $49,999     Rent   Single  F 
3:   $35,000 - $49,999            
4:                   
5:   $50,000 - $74,999 
str(df) 
Classes ‘data.table’ and 'data.frame': 999 obs. of 5 variables: 
$ age     : chr "" "35 - 44" "" "" ... 
$ income    : chr "$35,000 - $49,999" "$35,000 - $49,999" "$35,000 - $49,999" "" ... 
$ homeowner_status_desc: chr "" "Rent" "" "" ... 
$ marital_status_cd : chr "" "Single" "" "" ... 
$ gender    : chr "" "F" "" "" ... 
- attr(*, ".internal.selfref")=<externalptr> 

有遗漏的数据(它是空白)。在原始数据中,有很多列,因此我需要找到一种方法来创建列因子,只要列包含字符串。任何人都可以建议什么是最好的做法来完成这件事?我正在考虑将其更改为数据框并执行此操作。但它可以做到这一点,而它是一个data.table?

+2

从我的理解,data.table默认情况下不存储任何东西作为一个因素,以减少存储量。你必须自己改变一切因素。我有一行代码为我做了这个:'df [,(names(df)):= lapply(.SD,as.factor),。SDcols = names(df)]'。编辑:如果你只想要字符列,使用这个:'types < - data.frame(sapply(df,class)); char_list < - row.names(types)[types [[1]] =='character']'然后用'char_list'替换'names(df)' – Michal

+0

@Michal但因素需要更少的内存来储存 – rawr

+0

您是否试过在'fread'的'colClasses'参数中指定''factor''必要的地方? – MichaelChirico

回答

8

只要实现stringsAsFactors论据fread v中1.9.6+

NEWS来自:

  • 实施stringsAsFactors论据fread()。当TRUE时,字符列被转换为因子。默认为FALSE。感谢Artem Klevtsov提交#501,并感谢@ hmi2015对this SO post
  • 0

    这基本上是一个评论,但它很长,所以在这里。

    您可能想要使用colClasses指定哪些列是因素。

    如果你有很多列,这是我对我所做的简化是使用下面的函数我写道:

    abbr_to_colClass<-function(inits,counts){ 
        x<-substring(inits,1:nchar(inits),1:nchar(inits)) 
        types<-ifelse(x=="c","character", 
           ifelse(x=="f","factor", 
             ifelse(x=="i","integer", 
               "numeric"))) 
        rep(types,substring(counts,1:nchar(counts),1:nchar(counts))) 
    } 
    

    说你已经有了一个.csv与班列:

    character 3 
    factor 2 
    integer 1 
    numeric 5 
    character 6 
    

    然后,你可以用我的功能来设置

    colClasses=abbr_to_colClass("cfinc","32156") 
    

    这将特别SA如果你连续有一种类型的长字符串,则为空格。

    (我知道这是不是最强大的功能,但它的服务我很合适很多时候有要读很多领域)

    0

    我犯了一个小CSV文件,我可以证实相同的行为其中stringsAsFactors = TRUE不会生成因子列。另外指定colClasses作为因子似乎也不起作用。

    如果fread后运行这个它会所有你的性格列转换为因素

    for (j in which(sapply(df, class)=='character')) set(df, i=NULL, j=j, value=as.factor(df[[j]])) 
    
    0

    尝试新的readr包,它已被优化至10倍的速度更快,不会造成内存泄漏。您现在可以指定col_types参数,而不是stringsAsFactors,您可以在其中指定collector(自定义分析器函数)。看看文档,尤其是。 col_factor/parse_factor

    require(readr) 
    read_csv(..., col_types=...) 
    
    +0

    @Arun也许你必须先进行试验来编译关卡列表。可能使用'select'列参数。 – smci

    +0

    @阿伦:它看起来非常高效,哈德利做了一个大改写,人们广泛使用它,让我们从OP听到它是如何工作的......是的,它需要一点点努力来指定你的水平 – smci

    +0

    @阿伦:通常你可能只需要加载前n行来捕获所有因子水平,例如n〜100,000。对于OP来说,对于'readr'与'fread'的头对头表现数字是很好的。 – smci