使用R中的data.table将一列字符串拆分为可变数量的列

时间:2014-11-24 23:02:47

标签: r string data.table

我想分析许多年的Quicken家庭财务记录。我将文件导出到qif并使用bank2csv程序渲染csv。在Quicken中,可以使用类别(例如汽车,税收),子类别(例如汽车:服务,汽车:燃料)和标签(例如自己,配偶,儿子)。 bank2csv将类别:subcategories / tag呈现为连接字符串。我想将类别放在子类列中的类别列子类别中,并在标记列中放置任何标记。我看到a similar question但是唉,strsplit然后unlist工作,然后索引每个元素,以便可以通过赋值将其写入正确的位置。这在这里不起作用,因为有时没有标签,有时没有子类别。将字符串拆分为列表并将该列表保存在列中非常容易,但实际上如何将列表的第一个元素分配给一个列,将第二个元素(如果存在)分配给第二列。当然有一种优雅简单的方式。

简化样本

library(data.table)
library(stringi)
dt <- data.table(category.tag=c("toys/David", "toys/David", "toys/James", "toys", "toys", "toys/James"), transaction=1:6)

如何创建第三列和第四列:category,tag。部分标记为NA

我可以做到以下但是它并没有让我走得太远。我需要一种方法来指定结果列表的第一个或第二个元素(而不是整个列表)

dt[, category:= strsplit(x = category.tag, split = "/") ]

4 个答案:

答案 0 :(得分:6)

data.table v1.9.5 中推送了两个函数transpose()tstrsplit()

我们可以这样做:

require(data.table)
dt[, c("category", "tag") := tstrsplit(category.tag, "/", fixed=TRUE)]
#    category.tag transaction category   tag
# 1:   toys/David           1     toys David
# 2:   toys/David           2     toys David
# 3:   toys/James           3     toys James
# 4:         toys           4     toys    NA
# 5:         toys           5     toys    NA
# 6:   toys/James           6     toys James

tstrsplittranspose(strsplit(as.character(x), ...))的包装器。您还可以传递fill=.以使用NA以外的任何其他值填充缺失值。

transpose()也可用于列表数据框数据表

答案 1 :(得分:4)

您可以使用cSplit

library(splitstackshape)
dt[, c("category", "tag") := cSplit(dt[,.(category.tag)], "category.tag", "/")]
dt
#    category.tag transaction category   tag
# 1:   toys/David           1     toys David
# 2:   toys/David           2     toys David
# 3:   toys/James           3     toys James
# 4:         toys           4     toys    NA
# 5:         toys           5     toys    NA
# 6:   toys/James           6     toys James

答案 2 :(得分:2)

1)尝试read.table

read <- function(x) read.table(text = x, sep  = "/", fill = TRUE, na.strings = "")
dt[, c("category", "tag") := read(category.tag)]

不需要额外的包裹。

2)另一种方法是在tidyr包中使用separate

library(tidyr)
separate(dt, category.tag, c("category", "tag"), extra = "drop")

以上是来自github的tidyr版本0.1.0.9000。要安装它,请确保已安装devtools R软件包并发出命令:devtools::install_github("hadley/tidyr")

更新:注册Richard Scrivens&#39;评论和小改进。添加了泰迪尔解决方案。

答案 3 :(得分:1)

由于您已经加载了“stringi”,您还可以查看stri_split_fixedsimplify参数:

setnames(cbind(dt, stri_split_fixed(dt$category.tag, "/", simplify = TRUE)), 
         c("V1", "V2"), c("category", "tag"))[]
#    category.tag transaction category   tag
# 1:   toys/David           1     toys David
# 2:   toys/David           2     toys David
# 3:   toys/James           3     toys James
# 4:         toys           4     toys    NA
# 5:         toys           5     toys    NA
# 6:   toys/James           6     toys James

虽然我必须承认我偏爱cSplit: - )