【问题标题】:Split a column of strings into variable number of columns using data.table in R使用 R 中的 data.table 将一列字符串拆分为可变数量的列
【发布时间】:2015-01-22 19:32:31
【问题描述】:

我想分析 Quicken 多年的家庭财务记录。我将文件导出到 qif 并使用 bank2csv 程序渲染 csv。在 Quicken 中,可以使用一个类别(例如汽车、税收)、子类别(例如汽车:服务、汽车:燃料)和标签(例如,自我、配偶、儿子)。 bank2csv 将 categories: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)

如何创建第三和第四列:类别、标签。一些标签是NA

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

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

【问题讨论】:

    标签: r string data.table


    【解决方案1】:

    你可以使用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
    

    【讨论】:

    • cSplitconcat.split的缩写吗?
    • 我相信它是相似的,只是增加了一些功能
    • 我喜欢简洁优雅的线条。
    • @Farrel,本质上是一个别名。很多人抱怨concat.split打字太别扭,所以在我努力提高函数效率的时候,我把名字改成了cSplit
    • @Farrel,Rdocumentation 中“splitstackshape”的包版本是 1.2,但目前的版本是 1.4.2。 concat.split 本质上是 Gabor 的 read.table 方法,而 cSplit 是使用 strsplit 更快的实现。到 1.6 版时,我计划转移到 stri_split,这样会更快。这是一个(功能性)toy implementationcSplit 应该很快就会出现。
    【解决方案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 的评论和小幅改进。添加了 tidyr 解决方案。

    【讨论】:

    • 绝对精彩。现在我应该如何决定将“接受”授予谁。你或@RichardScriven。我喜欢被介绍给新的包,这可能会使我的生活更轻松地解决其他问题,但我再次假设当我使用新包而不是已经加载的函数时会有开销。
    • 获取Error in strsplit(value, sep, ...) : unused argument (extra = "drop")
    • 我使用的是 0.1 版
    【解决方案3】:

    由于您已经加载了“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 :-)

    【讨论】:

      【解决方案4】:

      刚刚在 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() 也可用于列表数据框数据表

      【讨论】:

        猜你喜欢
        • 2020-08-29
        • 1970-01-01
        • 1970-01-01
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 2021-10-29
        • 2019-12-24
        • 2023-03-20
        相关资源
        最近更新 更多