【问题标题】:Need to separate strings into multiple variables based on numeric versus non-numeric需要根据数字与非数字将字符串分成多个变量
【发布时间】:2020-01-26 00:06:20
【问题描述】:

我有一个带有一个变量的数据框。它看起来像这样:

df <- data.frame(c("25 Edgemont 52 Sioux County", "57 Burke 88 Papillion-LaVista South"))

为了提供更多背景信息,每个观察/行都是篮球比赛得分。我想分成四个数据框列,将数字和团队名称分开。例如,第一行将在第一列中以“25”结尾,在第二列中以“Edgemont”结尾,在第三列中以“52”结尾,在第四列中以 Sioux City 结尾。

我已经尝试了以下和各种 SO 建议,但无法获得预期的结果:

df2 <- strsplit(gsub("([0-9]*)([a-z]*)([0-9]*)([a-z]*)", "\\1 \\2 \\3 \\4", df), " ")

【问题讨论】:

  • 尝试library(stringr),然后尝试str_extract_all(df[[1]], "\\d+|[^\\d\\s](?:\\D*[^\\d\\s])?")

标签: r gsub strsplit


【解决方案1】:

1) dplyr/tidyr 用分号、那个数字和另一个分号替换每个数字,然后用分号和可选的周围空格分隔。

library(dplyr)
library(tidyr)

# input
df <- data.frame(V1 = c("25 Edgemont 52 Sioux County", 
                        "57 Burke 88 Papillion-LaVista South"))

df %>%
  mutate(V1 = gsub("(\\d+)", ";\\1;", V1)) %>%
  separate(V1, c(NA, "No1", "Let1", "No2", "Let2"), sep = " *; *")
##   No1       Let1 No2                     Let2
## 1  25  Edgemont   52             Sioux County
## 2  57     Burke   88  Papillion-LaVista South

1a) read.table 我们可以使用与 (1) 中相同的 gsub,然后使用 read.table 将其分开。没有使用任何包。

read.table(text = gsub("(\\d+)", ";\\1;", df$V1), sep = ";", as.is = TRUE,
  strip.white = TRUE, col.names = c(NA, "No1", "Let1", "No2", "Let2"))[-1]
##   No1     Let1 No2                    Let2
## 1  25 Edgemont  52            Sioux County
## 2  57    Burke  88 Papillion-LaVista South

2) strcapture 我们可以使用基础 R 中的strcapture

proto <- list(No1 = integer(0), Let1 = character(0),
              No2 = integer(0), Let2 = character(0))
strcapture("(\\d+) (.*) (\\d+) (.*)", df$V1, proto)
##   No1     Let1 No2                    Let2
## 1  25 Edgemont  52            Sioux County
## 2  57    Burke  88 Papillion-LaVista South

2a) read.pattern 我们可以使用 read.pattern 与 (2) 中相同的模式:

library(gsubfn)

read.pattern(text = format(df$V1), pattern = "(\\d+) (.*) (\\d+) (.*)", 
  col.names = c("No1", "Let1", "No2", "Let2"), as.is = TRUE, strip.white = TRUE)
##   No1     Let1 No2                    Let2
## 1  25 Edgemont  52            Sioux County
## 2  57    Burke  88 Papillion-LaVista South

【讨论】:

  • #1 (dplyr/tidyr/mutate/gsub) 完美运行 - 谢谢!
【解决方案2】:

1) 一个选项是extract from tidyr,我们在字符串的开头 (^) 提取一个或多个数字 ((\\d+)) 作为捕获组,后跟一个空格,然后是一个或多个带空格的字母字符,然后是一个空格,然后是捕获组中的一个或多个数字,然后是空格和其余字符作为第 4 列

library(stringr)
library(dplyr)
library(tidyr)
df %>% 
  extract(col1, into = str_c('col', 1:4),
           '^(\\d+) ([A-Za-z ]+) (\\d+) (.*)', convert  = TRUE)
#  col1     col2 col3                    col4
#1   25 Edgemont   52            Sioux County
#2   57    Burke   88 Papillion-LaVista South

2) 或者使用来自tidyrseparate,我们指定一个正则表达式环视来分割空间

df %>% 
   separate(col1, into = str_c('col', 1:4), sep = '(?<=\\d) | (?=\\d)')
#  col1     col2 col3                    col4
#1   25 Edgemont   52            Sioux County
#2   57    Burke   88 Papillion-LaVista South

3) 或者使用tstrsplit from data.table

library(data.table)
setDT(df)[, tstrsplit(col1, "(?<=\\d) | (?=\\d)", perl = TRUE)]
#   V1       V2 V3                      V4
#1: 25 Edgemont 52            Sioux County
#2: 57    Burke 88 Papillion-LaVista South

4) 或者使用来自base Rread.csv(不使用任何包...)

read.csv(text = gsub("(?<=\\d) | (?=\\d)", ",", df$col1, 
          perl = TRUE), header = FALSE)
#  V1       V2 V3                      V4
#1 25 Edgemont 52            Sioux County
#2 57    Burke 88 Papillion-LaVista South

5) 或者使用来自base Rstrsplit(不使用任何包...)

type.convert(as.data.frame(do.call(rbind, 
   strsplit(as.character(df$col1), "(?<=\\d) | (?=\\d)",
           perl = TRUE))), as.is = TRUE)
#  V1       V2 V3                      V4
#1 25 Edgemont 52            Sioux County
#2 57    Burke 88 Papillion-LaVista South

数据

df <- data.frame(col1 = c("25 Edgemont 52 Sioux County", 
             "57 Burke 88 Papillion-LaVista South"))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多