【问题标题】:Splitting cells in table while preserving other information拆分表格中的单元格,同时保留其他信息
【发布时间】:2014-04-26 08:18:48
【问题描述】:

我有一张表,我想在 R 中处理。其中两个单元存储以逗号分隔的坐标(开始和结束)。我想拆分这些坐标,使它们在自己的行上,但保留行中其他单元格的信息。

示例表:

header1  header2  start        end
data1    data2    1,100,200    99,199,299

期望的输出:

data1    data2    1     99
data1    data2    100   199
data1    data2    200   299

如何在 R 中做到这一点?

【问题讨论】:

  • 您能否使用dput(table)(其中“table”是对象的名称)提供您的“table”对象的实际结构作为对您问题的编辑?
  • 请参阅我的“splitstackshape”包中的concat.split.multiple。使用direction ="long"
  • "start"和"end"每行的分割值的个数是否总是一样的(本例中是三个值)?
  • @AnandaMahto 并不总是三个值。它从 1 到 737 不等。
  • @reedms,但是“start”和“end”每一行的item长度是一样的吧?

标签: r


【解决方案1】:

我假设您的表名为dfdata.table 包使这种重塑变得微不足道...

require(data.table)
dt <- as.data.table( df )
dt[ , list(start = strsplit(start , ",", fixed=TRUE)[[1]], 
           end   = strsplit(end , ",", fixed=TRUE)[[1]] 
          ), by = c("header1","header2") ]

#   header1 header2 start end
#1:   data1   data2     1  99
#2:   data1   data2   100 199
#3:   data1   data2   200 299

【讨论】:

  • 当我用我的真实数据集尝试这个时,它只适用于前 350 组坐标。它还要求我使用 strsplit(as.character(start), ",", fixed=TRUE)[[1]],
  • 所以发布你的数据的第 350/351 行......没有它就不可能说。
  • chrUn_random + 551804, 551833,\n chrUn_random + 552839, 552900,\n
  • 当我使用 by = c("header1", "header2) 时,它是否可能停止在 350,因为这是我的数据文件中每个特征的唯一组合的数量?
  • @reedms,如果是这样,那么添加一个新的 id 变量。
【解决方案2】:

我真的很喜欢 Simon 的 data.table 方法的优雅。这是一个老式的 R 版本:

# your original data
dat <- data.frame(header1="data1", header2="data2", 
                  start="1,100,200", end="99,199,299")
dat
##   header1 header2     start        end
## 1   data1   data2 1,100,200 99,199,299     

dat <- data.frame(dat[,c(1,2)],
             start=do.call('cbind', strsplit(as.character(dat$start), ',')),
             end=do.call('cbind', strsplit(as.character(dat$end), ',')))
dat
##   header1 header2 start end
## 1   data1   data2     1  99
## 2   data1   data2   100 199
## 3   data1   data2   200 299

【讨论】:

  • 当我使用这种方法时,我得到一个错误:“结果的行数不是向量长度的倍数(arg 1)”。
  • @reedms,你被要求提供一个可重现的例子,但还没有这样做。如果您这样做,我相信您获得的答案质量会有所提高,并帮助您更直接、更有效地解决问题。
  • @hrbrmstr,如果更多涉及代码is hidden behind a function,它仍然被认为是优雅的吗?另外,an ancient blog-post of mine....
【解决方案3】:

我实际上会编写一个如下所示的函数:

NewSplit <- function(indf, splitCols, sep = ",") {
  Keys <- setdiff(names(indf), splitCols)
  if (any(!vapply(indf[splitCols], is.character, logical(1L)))) {
    indf[splitCols] <- lapply(indf[splitCols], as.character)
  }
  X <- setNames(lapply(indf[splitCols], function(x) {
    strsplit(x, split = sep, fixed = TRUE)
  }), splitCols)
  Rep <- vapply(X[[1]], length, integer(1L))
  cbind(indf[rep(rownames(indf), Rep), Keys], 
        lapply(X, unlist), 
        row.names = NULL,
        stringsAsFactors = FALSE)
}

可以这样使用:

NewSplit(dat, c("start", "end"), ",")
#    header1 header2 id start end
# 1        A       F  1     1  99
# 2        A       F  1   100 199
# 3        A       F  1   200 299
# 4        B       G  1    11  33
# 5        B       G  1   222 444
# 6        C       H  1    10  72
# 7        D       I  1     7  10
# 8        D       I  1     8   9
# 9        D       I  1     9   8
# 10       D       I  1    10   7
# 11       D       I  1    11   6
# 12       E       J  1     1   3

其中“dat”定义为:

dat <- data.frame(
  header1 = LETTERS[1:5], header2 = LETTERS[6:10], 
  start = c("1,100,200", "11,222", "10", "7,8,9,10,11", "1"),
  end = c("99,199,299", "33,444", "72", "10,9,8,7,6", "3"))

dat$id <- with(dat, 
                ave(rep(1, nrow(dat)), 
                    header1, header2, 
                    FUN = seq_along))

这实际上是一个非常快的函数,因为使用的基本函数非常快。这是与 50K 行的“data.table”答案的比较。

将原始数据集扩展到 50K 行

dat2 <- do.call(rbind, replicate(10000, dat, FALSE))
dat2$id <- with(dat2, 
                ave(rep(1, nrow(dat2)), 
                    header1, header2, 
                    FUN = seq_along))
dim(dat2)
# [1] 50000     5
dt <- as.data.table(dat2)

创建几个函数来测试(为了方便)

fun1 <- function(dt = dt) {
  dt[, list(
    start = strsplit(as.character(start) , ",", fixed=TRUE)[[1]], 
    end   = strsplit(as.character(end) , ",", fixed=TRUE)[[1]]), 
    by = list(header1, header2, id)]
}

fun2 <- function(df = dat2) {
  NewSplit(df, c("start", "end"), ",")
}

检查它们是否相等

all.equal(as.data.frame(fun1(dt)), fun2(dat2))
# [1] TRUE

比较时间

system.time(fun1(dt))
#    user  system elapsed 
#   1.953   0.009   1.999 

system.time(fun2(dat2))
#    user  system elapsed 
#   0.286   0.001   0.288 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多