原文https://www.njtierney.com/post/2019/09/29/unexpected-function/
1.R语言允许使用函数作为参数。
2.在一个函数内部的函数可以自行修改。
啥意思呢?先创建一个自己的函数:
my_fun <- function(x, fun){
fun(x)
}
现在可以输入任何函数作为这个函数的参数。
以'dplyr'包的stroms
数据为例。
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
storms
## # A tibble: 10,010 x 13
## name year month day hour lat long status category wind pressure
## <chr> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr> <ord> <int> <int>
## 1 Amy 1975 6 27 0 27.5 -79 tropi… -1 25 1013
## 2 Amy 1975 6 27 6 28.5 -79 tropi… -1 25 1013
## 3 Amy 1975 6 27 12 29.5 -79 tropi… -1 25 1013
## 4 Amy 1975 6 27 18 30.5 -79 tropi… -1 25 1013
## 5 Amy 1975 6 28 0 31.5 -78.8 tropi… -1 25 1012
## 6 Amy 1975 6 28 6 32.4 -78.7 tropi… -1 25 1012
## 7 Amy 1975 6 28 12 33.3 -78 tropi… -1 25 1011
## 8 Amy 1975 6 28 18 34 -77 tropi… -1 30 1006
## 9 Amy 1975 6 29 0 34.4 -75.8 tropi… 0 35 1004
## 10 Amy 1975 6 29 6 34 -74.8 tropi… 0 40 1002
## # … with 10,000 more rows, and 2 more variables: ts_diameter <dbl>,
## # hu_diameter <dbl>
计算wind的均值:
my_fun(storms$wind, mean)
## [1] 53.495
也可以计算标准差、变异系数、中位数
my_fun(storms$wind, sd)
## [1] 26.21387
my_fun(storms$wind, var)
## [1] 687.1668
my_fun(storms$wind, median)
## [1] 45
更进一步,如果你想为按月汇总storms
的数据,怎么办?
storms %>%
group_by(month) %>%
summarise(wind_summary = mean(wind))
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 45.7
## 2 4 44.6
## 3 5 36.3
## 4 6 37.8
## 5 7 41.2
## 6 8 52.1
## 7 9 58.0
## 8 10 54.6
## 9 11 52.5
## 10 12 47.9
可以重复代码,把平均值函数改成其他函数就可以了,比如sd值。
storms %>%
group_by(month) %>%
summarise(wind_summary = sd(wind))
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 9.08
## 2 4 5.94
## 3 5 9.57
## 4 6 13.4
## 5 7 19.1
## 6 8 26.0
## 7 9 28.2
## 8 10 25.3
## 9 11 22.0
## 10 12 14.6
如此反复,周而复始,大脑感到很是乏累,有一个声音在脑海中响起:“别像猪一样”。
为了避免反复带来的麻烦,自己创建一个计算平均值的函数:
storms_wind_summary <- function(fun){
storms %>%
group_by(month) %>%
summarise(wind_summary = fun(wind))
}
现在就可以轻松传递函数名字给我们自己建立的函数了,比如mean:
storms_wind_summary(mean)
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 45.7
## 2 4 44.6
## 3 5 36.3
## 4 6 37.8
## 5 7 41.2
## 6 8 52.1
## 7 9 58.0
## 8 10 54.6
## 9 11 52.5
## 10 12 47.9
或者其他任何函数:
storms_wind_summary(sd)
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 9.08
## 2 4 5.94
## 3 5 9.57
## 4 6 13.4
## 5 7 19.1
## 6 8 26.0
## 7 9 28.2
## 8 10 25.3
## 9 11 22.0
## 10 12 14.6
storms_wind_summary(var)
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 82.5
## 2 4 35.3
## 3 5 91.5
## 4 6 180.
## 5 7 365.
## 6 8 678.
## 7 9 793.
## 8 10 638.
## 9 11 482.
## 10 12 213.
storms_wind_summary(median)
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <dbl>
## 1 1 50
## 2 4 45
## 3 5 35
## 4 6 35
## 5 7 37.5
## 6 8 45
## 7 9 50
## 8 10 50
## 9 11 50
## 10 12 45
甚至传递自己建立的函数为参数:
range_diff <- function(x){
diff(range(x))
}
storms_wind_summary(range_diff)
## # A tibble: 10 x 2
## month wind_summary
## <dbl> <int>
## 1 1 25
## 2 4 15
## 3 5 35
## 4 6 70
## 5 7 130
## 6 8 140
## 7 9 145
## 8 10 145
## 9 11 120
## 10 12 50
怎么样,看起来不错吧。自己就可以操纵函数。
更上一层楼
可以用summarise_at
实现相同的目的:
storms_wind_summary <- function(fun){
storms %>%
group_by(month) %>%
summarise_at(.vars = vars(wind),
.funs = list(fun))
}
storms_wind_summary(mean)
## # A tibble: 10 x 2
## month wind
## <dbl> <dbl>
## 1 1 45.7
## 2 4 44.6
## 3 5 36.3
## 4 6 37.8
## 5 7 41.2
## 6 8 52.1
## 7 9 58.0
## 8 10 54.6
## 9 11 52.5
## 10 12 47.9
storms_wind_summary(median)
## # A tibble: 10 x 2
## month wind
## <dbl> <dbl>
## 1 1 50
## 2 4 45
## 3 5 35
## 4 6 35
## 5 7 37.5
## 6 8 45
## 7 9 50
## 8 10 50
## 9 11 50
## 10 12 45
如果想传递许多函数,比如同时计算mean、median、sd、variance,怎么办?
可以用...来传递给函数,允许输入任何数目的函数为参数:
storms_wind_summary <- function(...){
storms %>%
group_by(month) %>%
summarise_at(.vars = vars(wind),
.funs = list(...))
}
storms_wind_summary(median, mean, max)
## # A tibble: 10 x 4
## month fn1 fn2 fn3
## <dbl> <dbl> <dbl> <int>
## 1 1 50 45.7 55
## 2 4 45 44.6 50
## 3 5 35 36.3 60
## 4 6 35 37.8 80
## 5 7 37.5 41.2 140
## 6 8 45 52.1 150
## 7 9 50 58.0 160
## 8 10 50 54.6 160
## 9 11 50 52.5 135
## 10 12 45 47.9 75
网友评论