在 R 中“分隔”列的更简洁选项(也许通过一些正则表达式)?

sym*_*ush 7 r tidyr

我有一个数据框,我想在其中分隔包含月份和年份的列:

\n
library(tidyverse)\ndf <- data.frame(\n  month_year = c("Januar / Janvier 1990", "Februar / F\xc3\xa9vrier 1990","M\xc3\xa4rz / Mars 1990")\n)\n\n# df\n#               month_year\n# 1  Januar / Janvier 1990\n# 2 Februar / F\xc3\xa9vrier 1990\n# 3       M\xc3\xa4rz / Mars 1990\n
Run Code Online (Sandbox Code Playgroud)\n

以下内容有效,但看起来有点笨拙:

\n
df %>% \n  separate(month_year, c("month","nothing","nothing2", "year"), sep = " ") %>%\n  select(-starts_with("nothing"))\n\n#     month year\n# 1  Januar 1990\n# 2 Februar 1990\n# 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n

是否有更简洁的选择来达到相同的结果?

\n

G. *_*eck 11

1) 单独使用 NA 省略不需要的字段,如下所示:

\n
library(tidyr)\n\ndf %>% separate(month_year, c("month", NA, "year"))\n##     month year\n## 1  Januar 1990\n## 2 Februar 1990\n## 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n

@Otto 指出这在 UTF8 中存在问题。如果这是您的情况,请添加显示的 sep= 值。 separate使用默认值,"[^[:alnum:]]+"它不处理 UTF8,但我们可以指定其中一个:

\n
    \n
  • "[^\\\\p{L}\\\\d]+"。它替换"[:alnum:]""\\\\p{L}"任何语言中的任何字母和"\\\\d"任何数字,或者
  • \n
  • "(*UCP)[^[:alnum:]]+"它使用 unicode 说明符作为前缀
  • \n
\n

这显示了一个例子。首先,我们创建一个显示问题的输入 df2,然后我们使用上面两个 sep 值之一。

\n
df <- data.frame(\n  month_year = c("Januar / Janvier 1990", "Februar / F\xc3\xa9vrier 1990","M\xc3\xa4rz / Mars 1990"))\ndf2 <- df %>% mutate(month_year = iconv(month_year, to = "UTF8"))\n\ndf2 %>% separate(month_year, c("month", NA, "year"), sep = "[^\\\\p{L}\\\\d]+")\n##     month year\n## 1  Januar 1990\n## 2 Februar 1990\n## 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n

2)read.table,这是一个基本解决方案:

\n
read.table(text = df[[1]], col.names = c("month", NA, NA, "year"))[-(2:3)]\n##     month year\n## 1  Januar 1990\n## 2 Februar 1990\n## 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n

3) read.pattern这使用read.pattern挑选出所需的字段。(\\\\w+)捕获第一个单词并(\\\\d+)捕获年份。

\n
library(gsubfn)\n\npat <- "(\\\\w+).* (\\\\d+)"\nread.pattern(text = df[[1]], pattern = pat, col.names = c("month", "year"))\n##     month year\n## 1  Januar 1990\n## 2 Februar 1990\n## 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n


r2e*_*ans 5

碱基R

\n
strcapture("^(.*)\\\\s+/.*\\\\s+([^\\\\s]+)$", df$month_year, proto = c(month="", year=1L))\n#     month year\n# 1  Januar 1990\n# 2 Februar 1990\n# 3    M\xc3\xa4rz 1990\n
Run Code Online (Sandbox Code Playgroud)\n

也许有点笨拙:

\n
setNames(do.call(rbind.data.frame,\n    lapply(strsplit(df$month_year, "\\\\s+"), function(z) z[c(1, length(z))])),\n  c("month", "year"))\n
Run Code Online (Sandbox Code Playgroud)\n

dplyr

\n

使用不同的正则表达式稍微减少代码:

\n
library(dplyr)\ndf %>%\n  separate(month_year, c("month", "ign", "year"), "[ /]+") %>%\n  select(-ign)\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
df %>%\n  mutate(month_year = gsub("/.* ", "", month_year)) %>%\n  separate(month_year, c("month", "year"), " ")\n
Run Code Online (Sandbox Code Playgroud)\n