用R中的最后两个字符拆分字符串? (/负字符串索引)

时间:2016-10-01 21:09:14

标签: r dataframe split

我的数据框架如下:

b <- data.frame(height = c(190,165,174,176), name = c('John Smith 34','Mr.Turner 54', 'Antonio P. 23', 'John Brown 31'))

#   height          name
# 1    190 John Smith 34
# 2    165  Mr.Turner 54
# 3    174 Antonio P. 23
# 4    176 John Brown 31

我们可以看到名称和年龄是相同的值。所以我想用字符串中的最后两个字符拆分它:

  height       name age
1    190 John Smith  34
2    165  Mr.Turner  54
3    174 Antonio P.  23
4    176 John Brown  31

我怎么能这样做?

5 个答案:

答案 0 :(得分:5)

tidyr::separate允许您传递分割位置的整数索引(包括从字符串末尾负向索引),从而使分隔列变得简单。 (当然,正则表达式也可以。)

library(tidyr)

b %>% separate(name, into = c('name', 'age'), sep = -4, convert = TRUE)
##   height        name age
## 1    190 John Smith   34
## 2    165  Mr.Turner   54
## 3    174 Antonio P.   23
## 4    176 John Brown   31

或以最终空格分开:

b %>% separate(name, into = c('name', 'age'), sep = '\\s(?=\\S*?$)', convert = TRUE)

返回同样的东西。

在基础R中,它需要更多工作:

b$name <- as.character(b$name)
split_name <- strsplit(b$name, '\\s(?=\\S*?$)', perl = TRUE)
split_name <- do.call(rbind, split_name)
colnames(split_name) <- c('name', 'age')
b <- data.frame(b[-2], split_name, stringsAsFactors = FALSE)
b$age <- type.convert(b$age)

b
##   height       name age
## 1    190 John Smith  34
## 2    165  Mr.Turner  54
## 3    174 Antonio P.  23
## 4    176 John Brown  31

答案 1 :(得分:3)

这里使用正则表达式的许多选项。我会使用substr,因为您想要确切地知道要提取的字符数。

data.table内(对于syntax-sugar):

library(data.table)
setDT(b)[,c("name","age"):=list(
  substr(name,1,nchar(name)-3),
  substr(name,nchar(name)-2,nchar(name)))]

   height       name age
1:    190 John Smith  34
2:    165  Mr.Turner  54
3:    174 Antonio P.  23
4:    176 John Brown  31

请注意,名称应为character

  b <- data.frame(
  height = c(190,165,174,176), 
  name = c('John Smith 34','Mr.Turner 54', 'Antonio P. 23', 'John Brown 31'),
  stringsAsFactors = FALSE)

答案 2 :(得分:1)

使用基数R(与@ agstudy的答案中使用的数据相同):

data.frame(t(apply(b,1,function(x) {s <- unlist(strsplit(trimws(x[2]), " "));
           c(x[1],paste0(head(s,-1),collapse=" "),tail(s,1)) })))

   # X1         X2 X3
# 1 190 John Smith 34
# 2 165  Mr.Turner 54
# 3 174 Antonio P. 23
# 4 176 John Brown 31

为了安全起见,我们按空格(即name)拆分修剪 strsplit(trimws(x[2]), " ")列并取最后一部分(即tail(s,1))作为age,其余(即head(s,-1))作为名称。

答案 3 :(得分:1)

就个人而言,我会发现以下正则表达式最有用。

library (stringr)
b $age <- str_extract (b$name, "\\d{1,3}$")
b $name <- str_replace (b $name,  "\\d{1,3}$", "")

这将在字符串末尾查找长度为1-3个字符的数字序列。可能有一种方法可以将其合并到separate语法中,但我是从手机上写的,无法探索。

这个正则表达式的优点是它可以处理单个,两个和三个数字的年龄,而不必依赖于存在的空间,或者必须从字符串的末尾开始倒数。

答案 4 :(得分:1)

我们可以使用,创建分隔符(sub)而不是年龄前的空格,使用read.tablecbind使用第一列使用{{ 1}}

base R

或使用cbind(b[1],read.table(text=sub("\\s+(\\d+)$", ", \\1", b$name), col.names = c("name", "age"), header=FALSE, sep=",")) # height name age #1 190 John Smith 34 #2 165 Mr.Turner 54 #3 174 Antonio P. 23 #4 176 John Brown 31

中的extract
tidyr