Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用r将多列拆分为多列_R_Split_Tidyr_Separator - Fatal编程技术网

使用r将多列拆分为多列

使用r将多列拆分为多列,r,split,tidyr,separator,R,Split,Tidyr,Separator,我有一个包含20列和300行的txt文件。我的数据样本如下所示 id sub A1 A2 B1 B2 C1 96 AAA 01:01:01:01/01:01:01:02N 29:02:01 08:01:01/08:19N 44:03:01/44:03:03/44:03:04 07:01:01/07:01:02 97 AAA 03:01:01:01

我有一个包含20列和300行的txt文件。我的数据样本如下所示

id  sub     A1                      A2      B1           B2                    C1   
96  AAA 01:01:01:01/01:01:01:02N        29:02:01    08:01:01/08:19N 44:03:01/44:03:03/44:03:04  07:01:01/07:01:02
97  AAA 03:01:01:01/03:01:01:02N        30:08:01    09:02:01/08:19N 44:03:01/44:03:03/44:03:04  07:01:01/07:01:02
98 AAA  01:01:01:01/01:01:01:02N/01:22N 29:02:01    08:01:01/08:19N 44:03:01/44:03:03/44:03:04  07:09:01/07:01:02
99  AAA 03:01:01:01                     30:08:01    09:02:01/08:19N 44:03:01/44:03:03/44:03:04  07:08:01/07:01:02 
我需要用分隔符“/”用r分隔列(A1、A2、B1…)。 产出将是:

   id   sub A1_1      A1_2         A2       B1_1     B1_2    B2_1  B2_2   ..
96  AAA 01:01:01:01   01:01:01:02N      29:02:01    08:01:01     08:19N      44:03:01  44:03:03   44:03:04  ...

我可以找到将一列拆分为多列的函数。但是我找不到一个解决方案来实现这一点。

我支持@Sotos的建议,写一个可复制的例子很重要,所以重点只放在手头的问题上

我用这些假数据来回答你的问题:

> df <- data.frame(
+   id = c(1:5),
+   sub = sample(c("GBR", "BRA"), size = 5, replace = T),
+   HLA_A = paste0(rep("01:01", 5), "/", rep("01:02N")), 
+   HLA_B = paste0(rep("01:03", 5), "/", "01:42N", "/", "32:20"), 
+   HLA_C = paste0(rep("01:03", 5)), stringsAsFactors = F)
> 
> 
> df
  id sub        HLA_A              HLA_B HLA_C
1  1 GBR 01:01/01:02N 01:03/01:42N/32:20 01:03
2  2 BRA 01:01/01:02N 01:03/01:42N/32:20 01:03
3  3 GBR 01:01/01:02N 01:03/01:42N/32:20 01:03
4  4 GBR 01:01/01:02N 01:03/01:42N/32:20 01:03
5  5 BRA 01:01/01:02N 01:03/01:42N/32:20 01:03

下面是一个
tidyverse
解决方案

library(tidyverse)
df %>% 
 gather(key, value, -c(1:2)) %>% 
 separate_rows(value, sep = "/") %>% 
 group_by(key, id) %>% 
 mutate(key2 = paste0(key, "_", seq_along(key))) %>%
 ungroup() %>% 
 select(-key) %>% 
 spread(key2, value)

# A tibble: 4 x 13
# id      sub   A1_1    A1_2     A1_3 A2_1 B1_1 B1_2 B2_1 B2_2 B2_3 C1_1 C1_2
#* <fct>   <fct> <chr>       <chr>        <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>   
#1 96 AAA   01:01:01:01 01:01:01:02N <NA>     29:02:01 08:01:01 08:19N   44:03:01 44:03:03 44:03:04 07:01:01 07:01:02
#2 97 AAA   03:01:01:01 03:01:01:02N <NA>     30:08:01 09:02:01 08:19N   44:03:01 44:03:03 44:03:04 07:01:01 07:01:02
#3 98 AAA   01:01:01:01 01:01:01:02N 01:22N   29:02:01 08:01:01 08:19N   44:03:01 44:03:03 44:03:04 07:09:01 07:01:02
#4 99 AAA   03:01:01:01 <NA>         <NA>     30:08:01 09:02:01 08:19N   44:03:01 44:03:03 44:03:04 07:08:01 07:01:02

我建议一种解决方案,注意不知道零件的数量:

> dput(pz1)
structure(list(id = c("HG00096", "HG00097", "HG00098", "HG00099"
), sub = c("GBR", "GBR", "GBR", "GBR"), HLA_A1 = c("01:01:01:01/01:01:01:02N", 
"03:01:01:01/03:01:01:02N", "01:01:01:01/01:01:01:02N/01:22N", 
"03:01:01:01"), HLA_A2 = c("29:02:01", "30:08:01", "29:02:01", 
"30:08:01"), HLA_B1 = c("08:01:01/08:19N", "09:02:01/08:19N", 
"08:01:01/08:19N", "09:02:01/08:19N"), HLA_B2 = c("44:03:01/44:03:03/44:03:04", 
"44:03:01/44:03:03/44:03:04", "44:03:01/44:03:03/44:03:04", "44:03:01/44:03:03/44:03:04"
), HLA_C1 = c("07:01:01/07:01:02", "07:01:01/07:01:02", "07:09:01/07:01:02", 
"07:08:01/07:01:02")), .Names = c("id", "sub", "HLA_A1", "HLA_A2", 
"HLA_B1", "HLA_B2", "HLA_C1"), row.names = c(NA, -4L), class = "data.frame")
添加此功能:

以及带有原始数据帧的简单cbind(带或不带原始列):


我会采取如下方法:

library(data.table)
setDT(df) # convert to a data.table

# identify the columns you want to split
cols <- grep("^HLA", names(df), value = TRUE)

# loop through them and split them
# assign them back to the data.table, by reference
for (i in cols) {
  temp <- tstrsplit(df[[i]], "/")
  set(df, j = sprintf("%s_%d", i, seq_along(temp)), value = temp)
  set(df, j = i, value = NULL)
}

除了比公认的答案更容易扩展(事情并不是真的硬编码)之外,这种方法的速度至少是这种方法的两倍,而且比“tidyverse”方法快得多,这种方法效率很低,因为它首先使数据在返回广泛格式之前很长一段时间


基准 要了解性能差异,请尝试以下操作:

library(data.table)
setDT(df) # convert to a data.table

# identify the columns you want to split
cols <- grep("^HLA", names(df), value = TRUE)

# loop through them and split them
# assign them back to the data.table, by reference
for (i in cols) {
  temp <- tstrsplit(df[[i]], "/")
  set(df, j = sprintf("%s_%d", i, seq_along(temp)), value = temp)
  set(df, j = i, value = NULL)
}
测试函数
myfun%
突变(键2=paste0(键“,”顺键“))%>%
解组()%>%
选择(-key)%%>%
排列(键2,值)
}

getIt您在第三排HLA_A1上有两个分隔符-您会期望什么?
separate(mydata,HLA_A2,into=c(“HLA_A1_1”,“HLA_A1_2”),sep=“/”)
将按说明进行操作,但跳过ie之后的任何字段。如第二行。因此,您是否事先不知道每个原始列的输出列数?@MonicaSteffiMatchado请对给出的答案进行反馈,不要忘了对解决问题的答案进行投票/检查。感谢您的解决方案。我得到了以下警告:警告消息:1:In(function(…,deparse.level=1):结果的列数不是向量长度的倍数(arg 1)1这显然是一个非常好的解决方案,尽管我不得不承认我很难掌握循环中发生的事情。(+1)@markus,中的
set()
函数“data.table”允许您在不复制的情况下替换值。因此,从需要拆分的列(
“cols”
)开始,我们(1)使用
tstrsplit()
将它们拆分,这将创建一个列表,其中每个项的长度相同(因此可以将它们视为列)。(2)使用列表的长度,我们在“j”参数中指定要创建的列的名称,并在“value”参数中指定要插入的值。(3)在对
set()
的另一个调用中使用“j”参数,我们还删除了拆分的原始列。对循环中的每一列重复此操作。
library("reshape2", lib.loc="~/R/win-library/3.3")

getIt <- function(df,col) {    
x <- max(sapply(strsplit(df[,col],split="/"),length))   ### get the max parts for column
q <- colsplit(string = df[,col],pattern="/",names = paste0(names(df)[col],"_",LETTERS[1:x]))
return(q) }
> getIt(pz1,3)
     HLA_A1_A     HLA_A1_B HLA_A1_C
1 01:01:01:01 01:01:01:02N         
2 03:01:01:01 03:01:01:02N         
3 01:01:01:01 01:01:01:02N   01:22N
4 03:01:01:01                      
> cbind(pz1[,1:2],getIt(pz1,3),getIt(pz1,4),getIt(pz1,5),getIt(pz1,6))
       id sub    HLA_A1_A     HLA_A1_B HLA_A1_C HLA_A2_A HLA_B1_A HLA_B1_B HLA_B2_A HLA_B2_B HLA_B2_C
1 HG00096 GBR 01:01:01:01 01:01:01:02N          29:02:01 08:01:01   08:19N 44:03:01 44:03:03 44:03:04
2 HG00097 GBR 03:01:01:01 03:01:01:02N          30:08:01 09:02:01   08:19N 44:03:01 44:03:03 44:03:04
3 HG00098 GBR 01:01:01:01 01:01:01:02N   01:22N 29:02:01 08:01:01   08:19N 44:03:01 44:03:03 44:03:04
4 HG00099 GBR 03:01:01:01                       30:08:01 09:02:01   08:19N 44:03:01 44:03:03 44:03:04
library(data.table)
setDT(df) # convert to a data.table

# identify the columns you want to split
cols <- grep("^HLA", names(df), value = TRUE)

# loop through them and split them
# assign them back to the data.table, by reference
for (i in cols) {
  temp <- tstrsplit(df[[i]], "/")
  set(df, j = sprintf("%s_%d", i, seq_along(temp)), value = temp)
  set(df, j = i, value = NULL)
}
df[]
#         id sub    HLA_A1_1     HLA_A1_2 HLA_A1_3 HLA_A2_1 HLA_B1_1 HLA_B1_2 HLA_B2_1 HLA_B2_2 HLA_B2_3 HLA_C1_1 HLA_C1_2
# 1: HG00096 GBR 01:01:01:01 01:01:01:02N       NA 29:02:01 08:01:01   08:19N 44:03:01 44:03:03 44:03:04 07:01:01 07:01:02
# 2: HG00097 GBR 03:01:01:01 03:01:01:02N       NA 30:08:01 09:02:01   08:19N 44:03:01 44:03:03 44:03:04 07:01:01 07:01:02
# 3: HG00098 GBR 01:01:01:01 01:01:01:02N   01:22N 29:02:01 08:01:01   08:19N 44:03:01 44:03:03 44:03:04 07:09:01 07:01:02
# 4: HG00099 GBR 03:01:01:01           NA       NA 30:08:01 09:02:01   08:19N 44:03:01 44:03:03 44:03:04 07:08:01 07:01:02
myfun <- function(df) {
  cols <- grep("^HLA", names(df), value = TRUE)
  for (i in cols) {
    temp <- tstrsplit(df[[i]], "/")
    set(df, j = sprintf("%s_%d", i, seq_along(temp)), value = temp)
    set(df, j = i, value = NULL)
  }
  df[]
}

tidyfun <- function(df) {
  df %>% 
    gather(key, value, -c(1:2)) %>% 
    separate_rows(value, sep = "/") %>% 
    group_by(key, id) %>% 
    mutate(key2 = paste0(key, "_", seq_along(key))) %>%
    ungroup() %>% 
    select(-key) %>% 
    spread(key2, value)
}

getIt <- function(df,col) {    
  x <- max(sapply(strsplit(as.character(df[,col]),split="/"),length))
  q <- colsplit(string = as.character(df[,col]),pattern="/",
                names = paste0(names(df)[col],"_",LETTERS[1:x]))
  return(q)
}    

reshape2fun <- function(dfdf) {
  cbind(dfdf[,1:2], getIt(dfdf,3), getIt(dfdf,4), getIt(dfdf,5), getIt(dfdf,6))
}
library(microbenchmark)
dfdf <- as.data.frame(df)
microbenchmark(myfun(copy(df)), reshape2fun(dfdf), tidyfun(df))
# Unit: microseconds
#               expr      min         lq       mean    median         uq      max neval
#    myfun(copy(df))   241.55   272.5965   625.7634   359.148   380.0395 28632.94   100
#  reshape2fun(dfdf)  5076.24  5368.3835  5841.8784  5539.577  5639.8765 34176.13   100
#        tidyfun(df) 37864.68 39435.1915 41152.5916 39801.499 40489.7055 70019.04   100
biggerdf <- rbindlist(replicate(2500, df, FALSE)) # nrow = 10,000
dfdf <- as.data.frame(biggerdf)
microbenchmark(myfun(copy(biggerdf)), reshape2fun(dfdf), tidyfun(biggerdf), times = 10)
# Unit: milliseconds
#                   expr        min        lq       mean     median         uq        max neval
#  myfun(copy(biggerdf))   50.87452   52.0059   54.59288   53.03503   53.79347   68.69892    10
#      reshape2fun(dfdf)  120.90291  124.3893  137.54154  126.06213  157.50532  159.15069    10
#      tidyfun(biggerdf) 1312.75422 1350.6651 1394.93082 1358.21612 1373.86793 1732.86521    10
BIGGERdf <- rbindlist(replicate(100, biggerdf, FALSE)) # nrow = 1,000,000
dfdf <- as.data.frame(BIGGERdf)
system.time(tidyfun(BIGGERdf)) # > 2 minutes!
#    user  system elapsed 
# 141.373   1.048 142.403 

microbenchmark(myfun(copy(BIGGERdf)), reshape2fun(dfdf), times = 5)
# Unit: seconds
#                   expr      min       lq     mean   median        uq       max neval
#  myfun(copy(BIGGERdf)) 5.180048 5.574677 6.026515 5.764467  6.498967  7.114415     5
#      reshape2fun(dfdf) 8.858202 9.095027 9.629969 9.264896 10.192161 10.739560     5