更简洁的选项来`分隔` R中的列(可能通过一些RegEx)?

htrmnn0y  于 2023-06-03  发布在  其他
关注(0)|答案(5)|浏览(285)

我有一个dataframe,我想分隔一个包含月份和年份的列:

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

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

8qgya5xd

8qgya5xd1#

1)separate使用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}""\\p{L}"是任何语言中的任何字母,"\\d"是任何数字,或
  • "(*UCP)[^[:alnum:]]+",使用unicode说明符作为前缀

这是一个例子。首先,我们创建一个显示问题的输入df 2,然后使用上面两个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)读取.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
2guxujil

2guxujil2#

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"))

dplyr

使用不同的正则表达式,对代码进行 * 非常轻微 * 的缩减:

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"), " ")
p1iqtdky

p1iqtdky3#

我们可以使用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
kx5bkwkv

kx5bkwkv4#

尝试使用以下基本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
xxe27gdn

xxe27gdn5#

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+'捕获所有数字; [^ /]捕获第一次出现/之前的子字符串。

相关问题