R-将数据帧中一列可变长度的字符串拆分为仅一个字符的多列

时间:2018-10-16 22:56:45

标签: r split

我有一个像这样的数据框:

Name     S1     S2     S3     Symbol
n_12     2.3    6.1    0      A
n_13     3.4    3.7    0      ACM
n_14     1.3    1.0    0      BN
n_23     2.0    4.1    0      NOPXY

我想将符号的最后一列分为多列,每列不包含一个字符或不包含任何字符。

    Name     S1     S2     S3     Sy1     Sy2     Sy3     Sy4     Sy5
    n_12     2.3    6.1    0      A                               
    n_13     3.4    3.7    0      A       C       M               
    n_14     1.3    1.0    0      B       N                       
    n_23     2.0    4.1    0      N       O       P       X       Y

谢谢您对此的任何帮助。

4 个答案:

答案 0 :(得分:6)

一种方法是使用def game_print(newlines_before, text, newlines_after) print ("\n" * newlines_before + text + "\n" * newlines_after) ,它将包含字符串的单个列拆分为包含子字符串的多个列。

tidyr::separate

df Name S1 S2 S3 Symbol 1 n_12 2.3 6.1 0 A 2 n_13 3.4 3.7 0 ACM 3 n_14 1.3 1.0 0 BN 4 n_23 2.0 4.1 0 NOPXY 的{​​{1}}参数接受正则表达式或列出要分割的字符串位置的数字矢量。由于我们想在每个字符后进行分割,因此我们希望给出一个从1到最长字符串(sep=的长度的数字序列,因为我们不需要在最后一个字符后进行分割)。最长字符串的长度用separate计算。感谢Rich Scriven指出-1是矢量化的,因此不需要使用max(nchar(.$Symbol))进行调用。

然后,我们使用要分隔nchar的列名称制作一个字符向量。就您而言,我们只需将sapply粘贴到相同的数字序列即可得到Symbol

'Sy'

如果出现以下错误:

c('Sy1', 'Sy2' ...)

然后,df %>% tidyr::separate(Symbol, sep = seq_len(max(nchar(.$Symbol)) - 1), into = paste0('Sy', seq_len(max(nchar(.$Symbol))))) Name S1 S2 S3 Sy1 Sy2 Sy3 Sy4 Sy5 1 n_12 2.3 6.1 0 A 2 n_13 3.4 3.7 0 A C M 3 n_14 1.3 1.0 0 B N 4 n_23 2.0 4.1 0 N O P X Y 的类型可能是Error in nchar(.$Symbol) : 'nchar()' requires a character vector (创建或加载df$Symbol时的默认值)而不是factor

您可以为data.framecharacter提供参数read.table,以防止将data.frame变量转换为stringsAsFactor=F或将其转换回Symbol

Tidyverse选项(可以在调用factor之前插入到管道中:

character

或以R为底的

tidyr::separate

答案 1 :(得分:3)

以下是使用strcapture的基本R版本:

ns <- max(nchar(dat$Symbol))
cbind(
  dat,
  strcapture(
    paste(rep("(.)", ns), collapse=""),
    format(dat$Symbol, width=ns),
    proto=setNames(rep(list(""), ns), paste0("Sy",1:ns))
  )
)

使用substring的后期基本R加法,它遍历每个输入,包括每个子字符串的开始和结束:

dat[paste0("Sy",seq(ns))] <- matrix(substring(rep(dat$Symbol,each=ns),
                                    seq(ns), seq(ns)), ncol=ns, byrow=TRUE)


#  Name  S1  S2 S3 Symbol Sy1 Sy2 Sy3 Sy4 Sy5
#1 n_12 2.3 6.1  0      A   A                
#2 n_13 3.4 3.7  0    ACM   A   C   M        
#3 n_14 1.3 1.0  0     BN   B   N            
#4 n_23 2.0 4.1  0  NOPXY   N   O   P   X   Y

答案 2 :(得分:1)

这是使用蛮力的R基:

string <- strsplit(df$Symbol, "")
ind <- max(lengths(string))
out <- data.frame(df, do.call(rbind, lapply(string, function(x) {
  if(length(x) !=  ind){
    c(x[1:length(x)], x[(length(x)+1):ind] )
  }else{
    x
  }
})))
names(out) <- sub("X(\\d)", "Sy\\1", names(out))
print(out, na.print = "")

  Name  S1  S2 S3 Symbol Sy1 Sy2 Sy3 Sy4 Sy5
1 n_12 2.3 6.1  0      A   A                
2 n_13 3.4 3.7  0    ACM   A   C   M        
3 n_14 1.3 1.0  0     BN   B   N            
4 n_23 2.0 4.1  0  NOPXY   N   O   P   X   Y

答案 3 :(得分:0)

出于完整性考虑,这里是单行data.table解决方案,使用tstrsplit()。将要添加的列数是动态的,并且基于Symbol的最大长度。

library(data.table)

dt <- fread("Name     S1     S2     S3     Symbol
n_12     2.3    6.1    0      A
n_13     3.4    3.7    0      ACM
n_14     1.3    1.0    0      BN
n_23     2.0    4.1    0      NOPXY")

dt[, paste0( "Sy", 1:length(tstrsplit(dt$Symbol, ""))) := tstrsplit( Symbol, "" )][]

#    Name  S1  S2 S3 Symbol Sy1  Sy2  Sy3  Sy4  Sy5
# 1: n_12 2.3 6.1  0      A   A <NA> <NA> <NA> <NA>
# 2: n_13 3.4 3.7  0    ACM   A    C    M <NA> <NA>
# 3: n_14 1.3 1.0  0     BN   B    N <NA> <NA> <NA>
# 4: n_23 2.0 4.1  0  NOPXY   N    O    P    X    Y