在同一数据框中,基于“:”分隔日期框中的多列?
Delimit multiple columns in a date frame based on ':', within that same dataframe?
我知道有很多问题问类似的问题,但我无法复制这些解决方案。
我有一个数据框如下:
vcf<-data.frame(
v1 = c(10, 15, 30),
v2 = c(10, 30, 80),
v3 = c(3,4,7),
v4 = as.factor(c('4:4:3','.','.')),
v5 = as.factor(c('4:7:2','4:2:7','3:5:7'))
)
我要实现的是最后两列一共分成六列:
vcf2<-data.frame(
v1 = c(10, 15, 30),
v2 = c(10, 30, 80),
v3 = c(3,4,7),
v4 = as.factor(c(4,'.','.')),
v5 = as.factor(c(4,'.','.')),
v6 = as.factor(c(3,'.','.')),
v7 = as.factor(c(4,4,3)),
v8 = as.factor(c(7,2,5)),
v9 = as.factor(c(2,7,7))
)
到目前为止我已经尝试了其他帖子的解决方案,我觉得最有希望的是:
within(vcf, vcf$v4<-data.frame(do.call('rbind',strsplit(as.character(vcf$v4), '\:', fixed=TRUE))))
但它并没有接近。
感谢任何帮助,谢谢。
您可以使用 stringr::str_split_fixed
:
library(stringr)
vcf_new <- cbind(vcf,str_split_fixed(vcf$v4, ":",3), str_split_fixed(vcf$v5, ":",3))
# drop the split columns
vcf_new <- vcf_new[,-c(4,5)]
# fix the names
names(vcf_new) <- paste0("v", seq(1,9))
# get rid of factors
vcf_new <- apply(vcf_new, 2, as.numeric)
v1 v2 v3 v4 v5 v6 v7 v8 v9
[1,] 10 10 3 4 4 3 4 7 2
[2,] 15 30 4 NA NA NA 4 2 7
[3,] 30 80 7 NA NA NA 3 5 7
如果您想要句点而不是 NA
s,您需要转换为字符类型,但这会起作用:vcf_new[is.na(vcf_new)] <- '.'
您可以折叠数据并使用 :
分隔符读取数据
read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":")
V1 V2 V3 V4 V5 V6 V7 V8 V9
1 10 10 3 4 4 3 4 7 2
2 15 30 4 . . . 4 2 7
3 30 80 7 . . . 3 5 7
要转换以上内容,只需添加参数 na.strings="."
即:
read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":",na.strings = ".")
您还可以使用 separate
编写递归方法,因为 separate 一次仅适用于一列:
library(tidyverse)
M = function(df,x,i=1,...){
df = separate(df,x[i],paste0(x[i],1:3),...)
if (i==length(x)) df else M(df,x,i+1,...)
}
M(vcf,c("v4","v5"))
v1 v2 v3 v41 v42 v43 v51 v52 v53
1 10 10 3 4 4 3 4 7 2
2 15 30 4 <NA> <NA> <NA> 4 2 7
3 30 80 7 <NA> <NA> <NA> 3 5 7
要将类型转换为数字:
M(vcf,c("v4","v5"),convert=T)
v1 v2 v3 v41 v42 v43 v51 v52 v53
1 10 10 3 4 4 3 4 7 2
2 15 30 4 NA NA NA 4 2 7
3 30 80 7 NA NA NA 3 5 7
一种选择是使用 data.table::tstrsplit
library(data.table)
setDT(vcf)
vcf[, paste0('v', 4:9) := sapply(.SD, tstrsplit, ':')
, .SDcols = c('v4', 'v5')]
vcf
# v1 v2 v3 v4 v5 v6 v7 v8 v9
# 1: 10 10 3 4 4 3 4 7 2
# 2: 15 30 4 . <NA> <NA> 4 2 7
# 3: 30 80 7 . <NA> <NA> 3 5 7
我知道有很多问题问类似的问题,但我无法复制这些解决方案。
我有一个数据框如下:
vcf<-data.frame(
v1 = c(10, 15, 30),
v2 = c(10, 30, 80),
v3 = c(3,4,7),
v4 = as.factor(c('4:4:3','.','.')),
v5 = as.factor(c('4:7:2','4:2:7','3:5:7'))
)
我要实现的是最后两列一共分成六列:
vcf2<-data.frame(
v1 = c(10, 15, 30),
v2 = c(10, 30, 80),
v3 = c(3,4,7),
v4 = as.factor(c(4,'.','.')),
v5 = as.factor(c(4,'.','.')),
v6 = as.factor(c(3,'.','.')),
v7 = as.factor(c(4,4,3)),
v8 = as.factor(c(7,2,5)),
v9 = as.factor(c(2,7,7))
)
到目前为止我已经尝试了其他帖子的解决方案,我觉得最有希望的是:
within(vcf, vcf$v4<-data.frame(do.call('rbind',strsplit(as.character(vcf$v4), '\:', fixed=TRUE))))
但它并没有接近。
感谢任何帮助,谢谢。
您可以使用 stringr::str_split_fixed
:
library(stringr)
vcf_new <- cbind(vcf,str_split_fixed(vcf$v4, ":",3), str_split_fixed(vcf$v5, ":",3))
# drop the split columns
vcf_new <- vcf_new[,-c(4,5)]
# fix the names
names(vcf_new) <- paste0("v", seq(1,9))
# get rid of factors
vcf_new <- apply(vcf_new, 2, as.numeric)
v1 v2 v3 v4 v5 v6 v7 v8 v9
[1,] 10 10 3 4 4 3 4 7 2
[2,] 15 30 4 NA NA NA 4 2 7
[3,] 30 80 7 NA NA NA 3 5 7
如果您想要句点而不是 NA
s,您需要转换为字符类型,但这会起作用:vcf_new[is.na(vcf_new)] <- '.'
您可以折叠数据并使用 :
分隔符读取数据
read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":")
V1 V2 V3 V4 V5 V6 V7 V8 V9
1 10 10 3 4 4 3 4 7 2
2 15 30 4 . . . 4 2 7
3 30 80 7 . . . 3 5 7
要转换以上内容,只需添加参数 na.strings="."
即:
read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":",na.strings = ".")
您还可以使用 separate
编写递归方法,因为 separate 一次仅适用于一列:
library(tidyverse)
M = function(df,x,i=1,...){
df = separate(df,x[i],paste0(x[i],1:3),...)
if (i==length(x)) df else M(df,x,i+1,...)
}
M(vcf,c("v4","v5"))
v1 v2 v3 v41 v42 v43 v51 v52 v53
1 10 10 3 4 4 3 4 7 2
2 15 30 4 <NA> <NA> <NA> 4 2 7
3 30 80 7 <NA> <NA> <NA> 3 5 7
要将类型转换为数字:
M(vcf,c("v4","v5"),convert=T)
v1 v2 v3 v41 v42 v43 v51 v52 v53
1 10 10 3 4 4 3 4 7 2
2 15 30 4 NA NA NA 4 2 7
3 30 80 7 NA NA NA 3 5 7
一种选择是使用 data.table::tstrsplit
library(data.table)
setDT(vcf)
vcf[, paste0('v', 4:9) := sapply(.SD, tstrsplit, ':')
, .SDcols = c('v4', 'v5')]
vcf
# v1 v2 v3 v4 v5 v6 v7 v8 v9
# 1: 10 10 3 4 4 3 4 7 2
# 2: 15 30 4 . <NA> <NA> 4 2 7
# 3: 30 80 7 . <NA> <NA> 3 5 7