【问题标题】:Change column class based on other data frame根据其他数据框更改列类
【发布时间】:2018-09-06 04:42:42
【问题描述】:

我有一个数据框,我正在尝试根据 col_type 转换 dt 的每个变量的类。 查找下面的示例以获取更多详细信息。

> dt
  id <- c(1,2,3,4)
   a <- c(1,4,5,6)
   b <- as.character(c(0,1,1,4))
   c <- as.character(c(0,1,1,0))
   d <- c(0,1,1,0)
  dt <- data.frame(id,a,b,c,d, stringsAsFactors = FALSE)

> str(dt)
'data.frame':   4 obs. of  5 variables:
 $ id: num  1 2 3 4
 $ a : num  1 4 5 6
 $ b : chr  "0" "1" "1" "4"
 $ c : chr  "0" "1" "1" "0"
 $ d : num  0 1 1 0

现在,我正在尝试根据以下数据框转换每一列的类。

> var  
  var <- c("id","a","b","c","d")
  type <- c("character","numeric","numeric","integer","character")
  col_type <- data.frame(var,type, stringsAsFactors = FALSE)


> col_type
  var      type
1  id character
2   a   numeric
3   b   numeric
4   c   integer
5   d character

我想将 id 转换为 col_type 数据框中提到的类,等等所有其他列。

我的尝试:

setDT(dt)
for(i in 1:ncol(dt)){
  if(colnames(dt)[i]%in%col_type$var){
    a <- col_type[col_type$var==paste0(intersect(colnames(dt)[i],col_type$var)),]
    dt[,col_type$var[i]:=eval(parse(text = paste0("as.",col_type$type[i],"(",col_type$var[i],")")))]
  }

}

注意-我的解决方案有效,但它真的很慢,我想知道我是否可以更有效、更干净地做到这一点。

我们将不胜感激。

【问题讨论】:

  • @Frank 我已编辑。

标签: r dataframe dplyr data.table plyr


【解决方案1】:

我将使用从col_type 表派生的colClasses 参数读取数据:

library(data.table)
library(magrittr)
setDT(col_type)

res = capture.output(fwrite(dt)) %>% paste(collapse="\n") %>% 
  fread(colClasses = col_type[, setNames(type, var)])

str(res)
Classes ‘data.table’ and 'data.frame':  4 obs. of  5 variables:
 $ id: chr  "1" "2" "3" "4"
 $ a : num  1 4 5 6
 $ b : num  0 1 1 4
 $ c : int  0 1 1 0
 $ d : chr  "0" "1" "1" "0"
 - attr(*, ".internal.selfref")=<externalptr> 

如果您可以在最初读入数据时执行此操作,则可以简化为...

 res = fread("file.csv", colClasses = col_type[, setNames(type, var)])

无需 data.table 即可轻松完成所有这些操作。


如果以某种方式从未将数据读入 R(作为 RDS 接收?),则:

setDT(dt)
res = dt[, Map(as, .SD, col_type$type), .SDcols=col_type$var]

str(res)
Classes ‘data.table’ and 'data.frame':  4 obs. of  5 variables:
 $ id: chr  "1" "2" "3" "4"
 $ a : num  1 4 5 6
 $ b : num  0 1 1 4
 $ c : int  0 1 1 0
 $ d : chr  "0" "1" "1" "0"
 - attr(*, ".internal.selfref")=<externalptr> 

【讨论】:

  • 我知道这个 colClasses 参数,但我不会写和读。我的数据量真的很大,不可行。
  • 还有其他方法可以让我的解决方案高效吗?
  • @Rushabh 您只将 R 中的数据存储在错误的列类中;在读入 R 之前不在磁盘上?效率不是很高,但您可以使用?as 函数进行转换,至少转换为您确定的类。但是,它很弱,例如as("2018-01-01", "Date") 失败。无论如何,我会编辑它。
  • 您的地图解决方案正在运行,但我收到警告“在 asMethod(object) 中:强制引入的 NA”
  • 好的,知道了。我真的很感谢你的帮助。学到了新东西。
【解决方案2】:

考虑Map 中的基本R 的get(),它可用于使用as.* 函数从其字符串文字中检索函数。然后将向量列表绑定到数据框中。

vec_list <- Map(function(v, t) get(paste0("as.", t))(dt[[v]]), col_type$var, col_type$type)

dt_new <- data.frame(vec_list, stringsAsFactors = FALSE)

str(dt_new)
# 'data.frame': 4 obs. of  5 variables:
# $ id: chr  "1" "2" "3" "4"
# $ a : num  1 4 5 6
# $ b : num  0 1 1 4
# $ c : int  0 1 1 0
# $ d : chr  "0" "1" "1" "0"

如果转换可能会失败,则可能将get() 包装在tryCatch 中。

【讨论】:

    猜你喜欢
    • 2020-02-18
    • 2019-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 2021-11-30
    • 1970-01-01
    相关资源
    最近更新 更多