R语言 使用purrr的功能编程
功能编程 是一种编程方法,我们通过构建和应用函数来构建程序。更具体地说,在程序中,我们应用顺序的纯函数而不是语句。一个纯函数是一个接受输入并产生一个一致的值作为输出的函数。同时,在这个过程中,没有任何增量或输入流被修改。这样的函数能够进行单一的操作,但为了进行复杂的操作,我们可以将它们组合成序列。
在本教程中,我们将讨论使用purr的函数式编程。如今,由于函数式编程具有解决复杂问题的能力,因此掌握它很重要。
R语言中的函数式编程
我们可以使用purrr包在R中实现函数式编程。你可以通过在CRAN中使用以下命令来安装purrr包—-。
install.packages("purrr")
正如你所看到的,我们已经在系统中成功安装了purrr包。
Map_()系列函数
purrr包为我们提供了map_()系列函数,使用它我们可以实现函数式编程,得到for和while循环的相同结果。
map_()函数有几种形式。让我们一个一个地看 –
map()函数
语法
这是最基本的函数。它接受一个向量和一个函数作为参数,然后为向量中的每个元素调用该函数。这个函数的语法如下。
map(vector, function)
它接受一个向量和一个函数作为参数。它返回一个列表作为输出。
示例
考虑下面给出的一个程序。
# Import library
library("purrr")
# Create a vector
myVector <- c(8, 3, 7, 2, 11, 20)
# Define a function
subtractByThree <- function(x) x - 3
# Print the output list
print(map(myVector, subtractByThree))
输出
[[1]]
[1] 5
[[2]]
[1] 0
[[3]]
[1] 4
[[4]]
[1] -1
[[5]]
[1] 8
[[6]]
[1] 17
正如你在上面看到的,从给定向量的所有元素中减去3后产生了一个列表。
示例
现在让我们再试着做一遍上面的事情,但这次是用循环。正如你在源代码中所看到的,这次在循环的情况下,我们需要写更复杂的代码。
# Create a vector
myVector <- c(8, 3, 7, 2, 11, 20)
# Create a list of size six
subtractByThree <- vector("list", 6)
# Iterate using a for loop
# and calculate the result
# for each value in the vector
for(currentNumber in seq_along(myVector)){
subtractByThree[[currentNumber]] <- myVector[currentNumber] - 3
}
# Print the list
print(subtractByThree)
输出
[[1]]
[1] 5
[[2]]
[1] 0
[[3]]
[1] 4
[[4]]
[1] -1
[[5]]
[1] 8
[[6]]
[1] 17
正如你在上面看到的,从给定向量的所有元素中减去3后产生了一个列表。
因此,我们可以说,在代码中使用map()可以减少代码的大小(与循环相比),而且我们也不需要创建一个空列表来保存结果。
map()函数还为我们提供了更简单的方法,根据位置和名称从一个向量中提取元素。比如说。
示例
在下面的程序中,我们创建了一个列表,我们先用位置来访问元素,然后用标题名称来访问。
# Import the library
library("purrr")
# Create a list of lists
myList <- list(list(data1 = 0.1, data2 = 1, data3 = "p"), list(data1 = 0.2, data2 = 4, data3 = "q"), list(data1 = 0.3, data2 = 8, data3 = "r")
)
# Access using position
map(myList, 2)
输出
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 8
使用标头名称访问
map(myList, "data3")
输出
[[1]]
[1] "p"
[[2]]
[1] "q"
[[3]]
[1] "r"
正如你在上面看到的,先打印第二位置的元素(使用position),然后是第三位置的(使用header name)元素。
map_chr()函数
语法
顾名思义,map_char()函数返回字符串的原子向量。这个函数的语法如下 –
map_chr(vector, function)
它接受一个向量和一个函数作为参数。它返回一个字符串的原子向量。
示例
让我们考虑一个说明该函数工作的程序–
# Import library
library("purrr")
# Create a vector
myVector <- c(8, 3, 7, 2, 11, 20)
# Define a function
subtractByThree <- function(x) x - 3
# Print the output list
print(map_chr(myVector, subtractByThree))
输出
[1] "5.000000" "0.000000" "4.000000" "-1.000000" "8.000000" "17.000000"
正如你在输出中看到的,操作的结果是以一个字符串的向量形式返回的。
map_dbl()函数
语法
顾名思义,map_dbl()函数返回双倍类型的原子向量。这个函数的语法如下 –
map_dbl(vector, function)
它接受一个向量和一个函数作为参数。它返回一个双倍类型的原子向量。
示例
让我们考虑一个说明该函数工作的程序–
# Import library
library("purrr")
# Create a vector
myVector <- c(8, 3, 7, 2, 11, 20)
# Define a function
subtractByThree <- function(x) x - 3
# Print the output list
print(map_dbl(myVector, subtractByThree))
输出
[1] 5 0 4 -1 8 17
正如你在输出中所看到的,操作的结果是作为一个双倍数据类型的向量返回的。
reduce()函数
语法
函数式编程的另一个动机是减少。purrr包为我们提供了reduce()函数,使用该函数我们可以将一个列表中的数值数量减少到一个单一的数值。这个函数的语法如下 –
reduce(list, operation)
它接受一个列表和要对列表中的值进行的操作。它返回一个单一的值。
示例
让我们考虑以下程序,演示reduce()函数的工作原理
# Import library
library("purrr")
# Apply reduce() function
reduce(seq(1:10), `*`)
输出
[1] 3628800
正如你所看到的,我们已经对列表中的所有元素进行了乘法运算,并产生了一个单一的值作为输出。
故障排除错误
在一个特定的程序或软件中排除问题的技能在开发领域相当重要。如果一个程序中涉及到列表,那么它就变得更加重要,因为在字符串的情况下,寻找问题变得很棘手。
安全()函数上的地图
当我们对一个列表进行映射时,有时一些操作的结果并不符合正确的数据类型。更确切地说,操作的结果是一个无效的值。在这种情况下,我们可以使用 safely() 函数来安全地清除。
在下面的程序中,我们要计算列表中所有元素的对数值。但是对于-1,不能计算对数。因此,它可能会引发一些错误。但是我们在这里使用 safely() 函数来映射,在这些操作过程中同时获得结果和错误。由于我们希望在得到任何错误之前就能得到结果,因此我们使用了transpose()函数。
示例
# Import library
library("purrr")
# Map using safely
myList <- list(12, 11, 10, -1) %>%
map(safely(log, otherwise = NA_real_)) %>%
# Transpose the outcome
transpose()
# Print the result
print(myList)
# Print the result component
print(myList[["Result"]])
# Print the error component
print(myList[["Error"]])
输出
$result
$result[[1]]
[1] 2.484907
$result[[2]]
[1] 2.397895
$result[[3]]
[1] 2.302585
$result[[4]]
[1] NaN
$error
$error[[1]]
NULL
$error[[2]]
NULL
$error[[3]]
NULL
$error[[4]]
NULL
打印结果组件
print(myList[["Result"]])
输出
NULL
打印错误组件
print(myList[["Error"]])
输出
NULL
正如你在输出中看到的,给定列表中各个元素的对数值已经显示出来了。由于列表中-1的对数无法计算,因此相应的输出值被NAN值所取代。你还可以在输出中分别看到结果部分和错误部分。
Map over possibly()函数
possibly()函数与 safely()函数的任务几乎相同。唯一的区别是 possibly() 不打印任何错误信息。
示例
让我们考虑下面的程序—
# Import library
library("purrr")
# Map over possibly()
myList <- list(12, 11, 10, -1) %>%
map(possibly(function(data){
log(data)
},NA_real_))
# Print the list
print(myList)
输出
[[1]]
[1] 2.484907
[[2]]
[1] 2.397895
[[3]]
[1] 2.302585
[[4]]
[1] NaN
正如你在输出中看到的,给定列表中各个元素的对数值已经显示出来了。由于列表中-1的对数无法计算,因此相应的输出值被NAN所取代。
结论
在本教程中,我们讨论了使用purrr包的函数编程。我们从什么是R中的purrr包以及如何使用CRAN安装它开始,然后我们看到了不同版本的map函数和它们的工作。最后,我们讨论了使用 safely() 和 possibly() 函数的故障排除方法。我希望这个教程能帮助你提高你在数据科学领域的知识。