【问题标题】:Split string in each column for several columns将每列中的字符串拆分为几列
【发布时间】:2015-11-07 01:21:58
【问题描述】:

我有这个表(data1)有四列

SNP rs6576700 rs17054099 rs7730126
sample1 G-G T-T G-G

我需要将 2-4 列分别分成两列,因此新输出有 7 列。像这样:

SNP rs6576700 rs6576700 rs17054099 rs17054099 rs7730126 rs7730126
sample1 G G T T C C

使用以下函数,我可以同时拆分所有列,但输出不是我需要的。

split <- function(x){
    x <- as.character(x)
    strsplit(as.character(x), split="-")
  }

data2=apply(data1[,-1], 2, split)

data2
$rs17054099
$rs17054099[[1]]
[1] "T" "T"


$rs7730126
$rs7730126[[1]]
[1] "G" "G"


$rs6576700
$rs6576700[[1]]
[1] "C" "C"

在 Stack Overflow 中,我找到了一种将 strsplit 的输出转换为数据帧的方法,但 rs 数字是在行中而不是在列中(我在这个线程中得到了与其他方法类似的输出 strsplit by row and distribute results by column in data.frame

> n <- max(sapply(data2, length))
> l <- lapply(data2, function(X) c(X, rep(NA, n - length(X))))
> data.frame(t(do.call(cbind, l)))
           t.do.call.cbind..l..
rs17054099                 T, T
rs7730126                  G, G
rs2061700                  C, C

如果我不使用函数 transpose (...(t(do.call...),输出是我无法写入文件的列表。

我想在 R 中提供解决方案,使其成为管道的一部分。

我忘了说我需要将此应用于一百万列。

【问题讨论】:

  • 您希望如何区分具有相同名称的列? ——提示:你不能。首先,您需要定义明确的列名。
  • 最后我不会使用标题。我想首先确定 SNP 的顺序。我可以添加 rs17054099.1 和 rs17054099.2。我需要创建一个 plink ped 文件,然后我将添加每个样本的信息(FID、IDD 等)。感谢您对我的问题感兴趣。萨米人
  • 好的,谢谢你的建议。如果列的顺序不改变标题并不重要。
  • This question is already answered here。 Data.table 也是一种非常快速的大数据解决方案。
  • @DavidArenburg 很高兴知道。自己没试过。我得再仔细看看。我在想lapply-tstrsplit 组合。当然cSplit 更直接。

标签: r strsplit


【解决方案1】:

使用splitstackshape::cSplit 函数很简单。只需在splitCols 参数中指定列索引,并在sep 参数中指定分隔符,您就完成了。它甚至会为您的新列名称编号,以便您能够区分它们。我已经指定了type.convert = FALSE,所以T 的值不会变成TRUE。默认方向为wide,无需指定。

library(splitstackshape)
cSplit(data1, 2:4, sep = "-", type.convert = FALSE)
#        SNP rs6576700_1 rs6576700_2 rs17054099_1 rs17054099_2 rs7730126_1 rs7730126_2
# 1: sample1           G           G            T            T           G           G

根据提供的链接,这是使用devel version of data.table on GHtstrsplit 函数的解决方案。在这里,我们将通过先分列列名来定义索引,然后我们将使用paste对其进行编号。这种方法有点麻烦,但它的优点是它会更新您的原始数据而不是创建副本全部数据

library(data.table) ## V1.9.5+
indx <- names(data1)[2:4]
setDT(data1)[, paste0(rep(indx, each = 2), 1:2) := sapply(.SD, tstrsplit, "-"), .SDcols = indx]
data1
#        SNP rs6576700 rs17054099 rs7730126 rs65767001 rs65767002 rs170540991 rs170540992 rs77301261 rs77301262
# 1: sample1       G-G        T-T       G-G          G          G           T           T          G          G

【讨论】:

  • 您好,谢谢您的回答。我尝试了 cSplit,但它不起作用。我忘了补充一点,我有一个包含近一百万列的文件,所以我需要一种方法来不指定当时的每一列。谢谢,
  • 究竟是什么不起作用?你能提供你的数据集的dput吗?请参阅我的编辑。您可以指定列索引而不是名称。例如,您可以执行2:1e3 之类的操作。
  • 这应该是我的错,我不能指定多个列 splitGeno1 = cSplit(data1, splitcols=data1[,2:4], seps="-") cSplit(data2, splitcols = data2) 中的错误[, 2:4], seps = "-") : 未使用的参数 (splitcols = data2[, 2:4], seps = "-")
  • 但是您使用了错误的语法。为什么data2[, 2:4]?这不是我展示的。试试cSplit(data2, splitcols = 2:4, seps = "-", type.convert = FALSE)
  • 我自己第一次尝试的时候错了。现在我尝试了你的命令,它工作得很好,非常感谢你,萨米
【解决方案2】:

在这里你想对行而不是列使用应用:

df <- rbind(c("SNP", "rs6576700", "rs17054099", "rs7730126"),
c("sample1", "G-G", "T-T", "G-G"),
c("sample2", "C-C", "T-T", "G-C"))

t(apply(df[-1,], 1, function(col) unlist(strsplit(col, "-"))))
#    [,1]      [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] "sample1" "G"  "G"  "T"  "T"  "G"  "G" 
#[2,] "sample2" "C"  "C"  "T"  "T"  "G"  "C"  

【讨论】:

  • 这是一个base 方法,速度慢得多,但仍然是一个很好的答案。
猜你喜欢
  • 2016-03-24
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2021-11-21
  • 2020-01-19
  • 1970-01-01
相关资源
最近更新 更多