2014-02-22 25 views
4

我有一个大型数据集,其中所有列标题都是单个IDS,每个IDS长度为8个字符。我想将这些单独的ID分成两行,第一行ID包含前7个字符,第二行仅包含最后一个字符。按R中的字母/字符数拆分列标签

当前数据集:

ID1: Indiv01A Indiv01B Indiv02A Indiv02B Speci03A Speci03B 

预期的数据集:

ID1: Indiv01 Indiv01 Indiv02 Indiv02 Speci03 Speci03 
ID2: A B A B A B 

我已经通过对分割数据的其他职位看,但他们似乎都不得不分开列名(一种独特的方式即:用逗号分隔两个组件,或一段时间)。

这是我想会的工作最好的代码,但我无法弄清楚如何为“7个字符”作为分割点代码,而不是一个逗号:

sapply(strsplit(as.character(d$ID), ",")

任何帮助,将不胜感激。

回答

7

下面是与strsplit解决方案的正则表达式。它分裂的第7和第8个字符的字符串:

ID1 <- c("Indiv01A", "Indiv01B", "Indiv02A", "Indiv02B", "Speci03A", "Speci03B") 

res <- strsplit(ID1, "(?<=.{7})", perl = TRUE) 

# [[1]] 
# [1] "Indiv01" "A"  
# 
# [[2]] 
# [1] "Indiv01" "B"  
# 
# [[3]] 
# [1] "Indiv02" "A"  
# 
# [[4]] 
# [1] "Indiv02" "B"  
# 
# [[5]] 
# [1] "Speci03" "A"  
# 
# [[6]] 
# [1] "Speci03" "B" 

现在,你可以使用rbind创建两列:

do.call(rbind, res) 
#  [,1]  [,2] 
# [1,] "Indiv01" "A" 
# [2,] "Indiv01" "B" 
# [3,] "Indiv02" "A" 
# [4,] "Indiv02" "B" 
# [5,] "Speci03" "A" 
# [6,] "Speci03" "B" 

的正则表达式的说明:

(?<=.{7}) 

(?<=)是一个(正面)向后看。它匹配指定模式之前的任何位置。这里的模式是.{7}。点(.)匹配任何字符。 {7}意味着7次。因此,正则表达式匹配前面恰好有7个字符的位置。

+0

+1比我的产品更优雅。你介意解释你的模式吗? – jbaums

+0

@jbaums我添加了一个解释。 –

+0

这是一个很好的解释和易于理解!我唯一的困难是,我仍然被卡住,试图将它应用到我的列标题或data.frame中的第一行。有什么想法吗?谢谢! – KKL234

1

有几种方法可以解决这个问题。

要提取的最后一个字符

首先,substr

new.vec <- sapply(old.vec, function(x) substr(x, nchar(x), nchar(x))) 

,或者与sub

new.vec <- sub('.*(.)', '\\1', old.vec) 

其中old.vec是要串的矢量分裂。

对于兴趣,后者选项使用regular expression其转换为:“捕获跟随零个或多个其他字符的单个字符(.)(.*)(通过用括号包围表示),并与所捕获的内容替换匹配(\\1)“。有关更多信息,请参见?gsubhere

上述选项允许改变字符串长度。但是,如果你做总是想后7个字符分割,字符串的第二部分总是有只是一个单一的字符,那么下面应该工作:

new.vec <- substr(old.vec, 8, 8) 

(编辑,包括方法提取字符串的第一部分。)

提取所有最后一个字符

这个过程是相似的。

new.vec <- sapply(old.vec, function(x) substr(x, 1, nchar(x) - 1)) 

new.vec <- sub('(.*).', '\\1', old.vec) 

new.vec <- substr(old.vec, 1, 7) 
+0

感谢您的快速响应!我已经尝试了选项1和3,并且由于试图指示要更改哪一行,我遇到了困难。数据集中的第一行(“年”)包含各个ID。我已经尝试了下面的代码,输出如下。 FK1split [1]“1”“1”“2”“2” “2”“2”“2”“2”“2”“2”“2”“2”“2”“2” > FK1split < - substr(FK1 $ Year,8,8) > FK1split [ 1]“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”有关如何轻松指示data.frame的哪一行应该被拆分的想法? – KKL234

+0

不要在第一个版本中将'x'更改为'7'和'1' - 您的更改只是提取'FK1 $ Year'每个元素的第一个字符。另外,要明白'substr(FK1 $ Year,8,8)'是为了提取'FK1 $ Year'每个元素的第8到第8(即只是第8个)字符。它看起来像'FK1 $ Year'可能没有8个字符。相应地调整“8”和“8”(它们指示开始和结束提取的位置)。顺便说一句,用反引号括起代码(通常在'〜'键上)来格式化注释中的代码。 – jbaums

2

这里是一个gsubfn解决方案:

library(gsubfn) 

strapplyc(ID1, "(.*)(.)", simplify = cbind) 

这给出了这样的矩阵:

 [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  
[1,] "Indiv01" "Indiv01" "Indiv02" "Indiv02" "Speci03" "Speci03" 
[2,] "A"  "B"  "A"  "B"  "A"  "B"  

,或者如果你想两列(而不是两行)代替cbind使用rbind

+0

感谢您突出显示此软件包 - 以前没有遇到过! – jbaums