如何编写可迭代的函数?

时间:2018-04-03 01:27:28

标签: r string function dataframe dplyr

我需要修改一个函数(下面),该函数将逐行应用dplyr::mutate删除任何'_'字符并将每个单词的第一个字母大写。

我的功能
simple_cap <- function(x) {
  s <- strsplit(x, "_")[[1]]
  paste(toupper(substring(s, 1,1)), substring(s, 2),
        sep="", collapse=" ")
}
我的数据
df <- read.table(text = c('
location             obs

1 australia         12454.
2 new_south_wales    3931.
3 victoria           3244.
4 queensland         2477.
5 south_australia     834.
6 western_australia  1335.
7 tasmania            246.'), stringsAsFactors = F)
dplyr::mutate来电:df %>% mutate( location = simple_cap(location) )
location   obs
1 Australia 12454
2 Australia  3931
3 Australia  3244
4 Australia  2477
5 Australia   834
6 Australia  1335
7 Australia   246
输出
df$location

如何更改我的功能,以便它可以用来迭代greatest()中的值,而不是用第一个元素的输出替换它们?

3 个答案:

答案 0 :(得分:3)

1)使用gsub

我们可以使用gsub选择小写字符([a-z]),捕获为字符串的第一个字母组{({1}})((...) )或(^)在下划线(|)之后,并在转换为大写(_)之后用反向引用替换

使用其他\\U换行删除gsub并替换为_

" "

2)使用stringi

或其他选项df %>% mutate(location = gsub("_", " ", gsub("(^|_)([a-z])", "\\1\\U\\2", location, perl = TRUE))) # location obs #1 Australia 12454 #2 New South Wales 3931 #3 Victoria 3244 #4 Queensland 2477 #5 South Australia 834 #6 Western Australia 1335 #7 Tasmania 246 来自stri_trans_totitle

stringi

3)使用OP的修改功能

library(stringi) df %>% mutate(location = stri_trans_totitle(stri_replace_all_fixed(location, "_", " "))) # location obs #1 Australia 12454 #2 New South Wales 3931 #3 Victoria 3244 #4 Queensland 2477 #5 South Australia 834 #6 Western Australia 1335 #7 Tasmania 246 输出为strsplit。在OP的代码中,它只是通过提取list来对第一个元素进行子集化。但是,这里我们有[[1]]长度为7.因此,一个选项是使用list中的map(或来自purrr的{​​{1}})然后执行lapply/sapply

base R
paste

4)OP的修改功能

substring

5)没有外部包

但是,这可以在不使用任何外部包的情况下完成

simple_cap <- function(x) {
  s <- strsplit(x, "_")
  purrr::map_chr(s,  ~
    paste(toupper(substring(.x, 1,1)), substring(.x, 2),
         sep="", collapse=" "))
 }

df %>%
     mutate(location = simple_cap(location))
#           location   obs
#1         Australia 12454
#2   New South Wales  3931
#3          Victoria  3244
#4        Queensland  2477
#5   South Australia   834
#6 Western Australia  1335
#7          Tasmania   246

答案 1 :(得分:2)

str_to_title中的stringr函数将单词的第一个字符大写,gsub我们将所有“_”(下划线)替换为“”(空格)。

library(stringr)
library(dplyr)

df %>%
   mutate(location = str_to_title(gsub("_", " ", location)))


#           location   obs
#1         Australia 12454
#2   New South Wales  3931
#3          Victoria  3244
#4        Queensland  2477
#5   South Australia   834
#6 Western Australia  1335
#7          Tasmania   246

答案 2 :(得分:2)

Ronak Shah和akrun解决了你的具体问题。这是标题问题的一般解决方案(如何编写可迭代的函数)。

在R的说法中,您需要一个矢量化函数 - 一个接受矢量输入并返回矢量输出的函数。有两种方法可以做到这一点。

1)确保函数中的每一步都可以接受矢量输入并返回矢量输出。 @ akrun的第4个答案标识了代码中阻止它执行此操作的步骤s <- strsplit(x, "_")[[1]]

2)将非向量化函数转换为带Vectorize的向量化函数。 选项1效率更高,但有时却无法实现。这显然是一个可行的示例,但为了向您展示这是如何工作的,让我们使用Vectorize

向您的函数进行矢量化
simple_cap <- function(x) {
  s <- strsplit(x, "_")[[1]]
  paste(toupper(substring(s, 1,1)), substring(s, 2),
        sep="", collapse=" ")
}

simple_cap_v <- Vectorize(simple_cap, USE.NAMES = FALSE)
simple_cap(df$location)
# [1] "Australia"
simple_cap_v(df$location)
# [1] "Australia"         "New South Wales"   "Victoria"          "Queensland"       
# [5] "South Australia"   "Western Australia" "Tasmania"  

df %>% mutate(
  location = simple_cap_v(location)
)
#            location   obs
# 1         Australia 12454
# 2   New South Wales  3931
# 3          Victoria  3244
# 4        Queensland  2477
# 5   South Australia   834
# 6 Western Australia  1335
# 7          Tasmania   246

Vectorize返回一个函数,它是mapply的包装器。实际上,对simple_cap_v(x)的调用现在是mapply(simple_cap, x, USE.NAMES = FALSE)