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



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

library(tidyverse)
df <- data.frame(
month_year = c("Januar / Janvier 1990", "Februar / Février 1990","März / Mars 1990")
)
# df
#               month_year
# 1  Januar / Janvier 1990
# 2 Februar / Février 1990
# 3       März / Mars 1990

以下有效,但似乎有点笨拙:

df %>% 
separate(month_year, c("month","nothing","nothing2", "year"), sep = " ") %>%
select(-starts_with("nothing"))
#     month year
# 1  Januar 1990
# 2 Februar 1990
# 3    März 1990

有没有更简洁的选项来实现相同的结果?

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

library(tidyr)
df %>% separate(month_year, c("month", NA, "year"))
##     month year
## 1  Januar 1990
## 2 Februar 1990
## 3    März 1990

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

  • "[^\p{L}\d]+". 这会将"[:alnum:]"替换为"\p{L}", 是任何语言的任何字母,"\d"是任何数字,或
  • "(*UCP)[^[:alnum:]]+"使用 Unicode 说明符作为前缀

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

df <- data.frame(
month_year = c("Januar / Janvier 1990", "Februar / Février 1990","März / Mars 1990"))
df2 <- df %>% mutate(month_year = iconv(month_year, to = "UTF8"))
df2 %>% separate(month_year, c("month", NA, "year"), sep = "[^\p{L}\d]+")
##     month year
## 1  Januar 1990
## 2 Februar 1990
## 3    März 1990

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

read.table(text = df[[1]], col.names = c("month", NA, NA, "year"))[-(2:3)]
##     month year
## 1  Januar 1990
## 2 Februar 1990
## 3    März 1990

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

library(gsubfn)
pat <- "(\w+).* (\d+)"
read.pattern(text = df[[1]], pattern = pat, col.names = c("month", "year"))
##     month year
## 1  Januar 1990
## 2 Februar 1990
## 3    März 1990

base R

strcapture("^(.*)\s+/.*\s+([^\s]+)$", df$month_year, proto = c(month="", year=1L))
#     month year
# 1  Januar 1990
# 2 Februar 1990
# 3    März 1990

也许有点笨拙:

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

德普利尔

使用不同的正则表达式对代码进行轻微的减少:

library(dplyr)
df %>%
separate(month_year, c("month", "ign", "year"), "[ /]+") %>%
select(-ign)

df %>%
mutate(month_year = gsub("/.* ", "", month_year)) %>%
separate(month_year, c("month", "year"), " ")

我们可以使用stringr包中的word

library(dplyr)
library(stringr)
df %>% 
mutate(month = word(month_year, 1),
year = word(month_year, 4), .keep="unused")
month year
1  Januar 1990
2 Februar 1990
3    März 1990

尝试使用以下基本 R 代码,其中包含read.table+gsub

read.table(
text = c(names(df), gsub("\s+.*\s+", "_", df$month_year)),
sep = "_",
header = TRUE
)

这给了

month year
1  Januar 1990
2 Februar 1990
3    MΣrz 1990

Tidyverse + stringr

library(stringr)
df %>% mutate(year = as.numeric(str_extract(.$month_year, '\d+'))) %>%
mutate(month = str_extract(.$month_year, '[^ /]+') )
month_year year   month
1  Januar / Janvier 1990 1990  Januar
2 Februar / Février 1990 1990 Februar
3       März / Mars 1990 1990    März

'\d+'捕获所有数字;[^ /]在第一次出现/之前捕获子字符串。

最新更新