如何实现在 R 中的数据帧列表上调用特定列名的函数?lapply 错误

How do I implement a function that calls specific column names on a list of data frames in R? Error with lapply

提问人:twilightecologist 提问时间:11/16/2023 最后编辑:halfertwilightecologist 更新时间:11/17/2023 访问量:71

问:

我对 R 很陌生。我想使用一个执行多个计算的函数,这些计算在数据框中的列之间进行计算,并创建保存最终计算的新列。我想在数据帧列表中实现此函数,但是,当我尝试使用 lapply 时,我收到一个错误,指出缺少第一列名称且没有默认值。

我知道这一定是我格式化函数的问题,但是我正在努力为此想出解决方案。我该如何进行?

#create example data frames, my real data frames are named similarly, with an identical names and a unique id (i.e. example_df_uniqueidnumber), each data frame has columns named identically

df1 <- data.frame(pt1_X = c(1,2,3), pt2_X = c(1,2,3), pt1_Y = c(1,2,3), pt2_Y =c(1,2,3))
df2 <- data.frame(pt1_X = c(1,2,3), pt2_X = c(1,2,3), pt1_Y = c(1,2,3), pt2_Y =c(1,2,3))


#create my example function
#NOTE: I call the data "data" (instead of df1 or df2), because I am unsure of what to use instead, as each file name is different due to the unique identifier 

calculate_angles1 <- function(data, pt1_X, pt1_Y, pt2_X, pt2_Y) {
  data$Mx <- (data[[pt1_X]] - data[[pt2_X]])
  data$My <- (data[[pt1_Y]] - data[[pt2_Y]])
    return(data)
}

#create my list of data frames
new_list <- list(df1, df2)


#use lapply to attempt to apply my function to my list of data frames 
AoA <- lapply(new_list, calculate_angles1)

运行lapply函数后,收到此错误消息。

Error in (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x,  : 
  argument "pt1_X" is missing, with no default
R DataFrame 函数 矩阵 lapply

评论


答:

0赞 jkatam 11/16/2023 #1

请尝试以下代码


library(dplyr)
library(purrr)

new_list <- list(df1, df2)

map(new_list, \(x) {
  x <- x %>% mutate(mx=pt1_X-pt2_X, my=pt1_Y-pt2_Y)
  return(x)
})


[[1]]
  pt1_X pt2_X pt1_Y pt2_Y mx my
1     1     1     1     1  0  0
2     2     2     2     2  0  0
3     3     3     3     3  0  0

[[2]]
  pt1_X pt2_X pt1_Y pt2_Y mx my
1     1     1     1     1  0  0
2     2     2     2     2  0  0
3     3     3     3     3  0  0

0赞 I_O 11/16/2023 #2

要使用 ,您需要将列名引起来:calculate_angles2

calculate_angles2(df1, 'pt1_X', 'pt2_X', 'pt1_Y', 'pt2_Y')

或者,如果您坚持使用不带引号的名称,则可以在 base R 中执行此操作:

calculate_angles3 <- function(data, a, b, c, d){
  data$Mx <- eval(substitute(a-b), data)
  data$My <- eval(substitute(c-d), data)
  data
}

calculate_angles3(df1, pt1_X, pt2_X, pt1_Y, pt2_Y)

(或使用 {rlang} 提供的附加功能进行非标准评估

0赞 Friede 11/16/2023 #3

从这里开始:

calculate_angles1 <- function(data) {
  Mx <- data[, "pt1_X"] - data[, "pt2_X"]
  My <- data[, "pt1_Y"] - data[, "pt2_Y"]
  do.call("cbind", list(data, "Mx" = Mx, "My" = My))
}

lapply(new_list, calculate_angles1)

0赞 MrFlick 11/16/2023 #4

您定义了函数以包含一堆未提供且未定义默认值的其他参数。您只需更改功能即可使事情变得更容易。lapplycalculate_angles1

calculate_angles1 <- function(data) {
  data$Mx <- (data$pt1_X - data$pt2_X)
  data$My <- (data$pt1_Y - data$pt2_Y)
  return(data)
}

调用 时,R 会查找名为 的变量以获取列信息。如果你这样做了并运行了,你会看到你得到的是“pt2_Y”列,而不是“pt1_X”。这与从 data.frame 中提取列不同。data[[pt1_X]]pt1_Xpt1_X <- "pt2_Y"df1[[pt1_X]]data$pt1_Xpt1_X

0赞 SAL 11/16/2023 #5

函数的问题在于名称必须用双引号括起来。此外,要处理变量值,请使用 single 而不是 double 。 因此,该函数可以重写为:[[[

 calculate_angles1 <- function(data) {
  data["Mx"] <- data["pt1_X"] - data["pt2_X"]
  data["My"] <- data["pt1_Y"] - data["pt2_Y"]
  data.frame(data)
}

要将您的函数应用于数据帧列表,有多种方法,如您所述:lapply

lapply

 new_list <- lapply(new_list,  calculate_angles1)

或者使用包或系列中的功能,我认为这会更直接。就像您的函数一样,它以数据帧作为第一个参数并返回数据帧。因此,您可以像我在这里所做的那样调用动词来操作内部的数据,即调用 from 来创建新变量。map()purrrtidyverseData frame functiondplyrmapmutate()dplyr

地图

library(tidyverse)
new_list <- map(new_list, ~ mutate(.x, Mx=pt1_X-pt2_X, My=pt1_Y-pt2_Y))

这两个选项都会产生相同的输出:

> new_list
[[1]]
  pt1_X pt2_X pt1_Y pt2_Y Mx My
1     1     1     1     1  0  0
2     2     2     2     2  0  0
3     3     3     3     3  0  0

[[2]]
  pt1_X pt2_X pt1_Y pt2_Y Mx My
1     1     1     1     1  0  0
2     2     2     2     2  0  0
3     3     3     3     3  0  0

评论

1赞 halfer 11/17/2023
问为什么有人投反对票几乎没有任何意义。如果他们打算告诉你,他们会这样做,否则他们早就走了,他们不会看到你的询问。