在R中跨列应用用户定义函数

4

我有两个R函数,可以将弧度和角度转换为笛卡尔坐标:

x_cart<-function(theta,r){
  return(r * cos (theta))
}
y_cart<-function(theta,r){
  return(r * sin (theta))
}

我想应用此函数在数据框中创建两个新列 xy,从列 angleradius 中获得。当我使用 lapply 时,会出现一个错误,显示参数 r 缺失且没有默认值。

df$x<-apply(df[,c("angle_adj","hit_distance")],1, x_cart())

测试数据

angle<-c(10,15,20)
radius<-c(15,35,10)
df<-data.frame(angle,radius)
5个回答

5
一种整洁易懂的R语言包选项。
library(dplyr)

df %>%
  mutate(X = x_cart(angle, radius),
         Y = y_cart(angle, radius))

#   angle radius          X         Y
# 1    10     15 -12.586073 -8.160317
# 2    15     35 -26.589077 22.760074
# 3    20     10   4.080821  9.129453

4
您不需要使用 apply,可以尝试使用以下代码:
x_cart<-function(theta,r){
  return(r * cos (theta))
}
y_cart<-function(theta,r){
  return(r * sin (theta))
}

angle<-c(10,15,20)
radius<-c(15,35,10)
df<-data.frame(angle,radius)

df$x <- x_cart(df$angle, df$radius)

# or using with()
df$x <- with(df, x_cart(angle, radius))

甚至更加紧凑:

cart <- function(theta,r){
  r * c(cos(theta), sin(theta))
}

df <- data.frame(
  angle = c(10, 15, 20),
  radius = c(15, 35, 10)
)

df[c("x", "y")] <- cart(df$angle, df$radius)

2

更新

感谢亲爱的@ThomasIsCoding提供的输入,我们可以节省一行额外的代码,并使用基本的R语言新的本地管道:

sapply(c(x_cart,y_cart),function(f) mapply(f,df1$angle, df1$radius)) |>
  data.frame() |>
  cbind(df1) -> df2

colnames(df2) <- c("x", "y", "angle", "radius")
df2

           x         y angle radius
1 -12.586073 -8.160317    10     15
2 -26.589077 22.760074    15     35
3   4.080821  9.129453    20     10

你也可以使用 tidyverse 来更加自动化这个过程:

library(dplyr)
library(purrr)

# First wrap our arguments in a list
lst <- list(df1$angle, df1$radius)

# Then we create a character vector of our function names
c("x_cart", "y_cart") %>%
  map(~ exec(.x, !!!lst)) %>%
  set_names(nm = c("x", "y")) %>%
  bind_cols() %>%
  bind_cols(df)

# A tibble: 3 x 4
       x     y angle radius
   <dbl> <dbl> <dbl>  <dbl>
1 -12.6  -8.16    10     15
2 -26.6  22.8     15     35
3   4.08  9.13    20     10

1
一个相当复杂的策略,但我喜欢使用NSE /准引用的努力!您可以看到他的自定义函数是矢量化的,在这里不需要调用mapply。 - GuedesBF
谢谢亲爱的@GuedesBF,你真是太好了。这对我来说是一个奇怪的情况,因为我比较擅长这些东西,而基础R却需要我努力学习。 - Anoushiravan R

1

一种使用apply的基本R解决方案。在这种情况下,重新定义您的函数会更好:

x_cart_2 <- function(input) { return(input[2] * cos(input[1])) }

df$x <- apply(df[,c("angle","radius")],1, x_cart_2)

返回
  angle radius          x
1    10     15 -12.586073
2    15     35 -26.589077
3    20     10   4.080821

1
尝试像下面这样使用 sapply
cbind(
  df,
  sapply(
    setNames(c(x_cart, y_cart), c("x", "y")),
    function(f) with(df, f(angle, radius))
  )
)

这提供了

  angle radius          x         y
1    10     15 -12.586073 -8.160317
2    15     35 -26.589077 22.760074
3    20     10   4.080821  9.129453

亲爱的Thomas,我可以问一下你是否有任何建议让我能够将这两个mapply函数写在一起,而不是分成两行吗? - Anoushiravan R
1
@AnoushiravanR 我猜你可以使用sapply(c(x_cart,y_cart),function(f) mapply(f,df1$angle, df1$radius) - ThomasIsCoding
非常感谢。我会将其添加到我的解决方案中。我真的很感激。很奇怪,我在我的第二个解决方案中使用了相同的策略,但当涉及基本R时,我脑海中没有任何想法! - Anoushiravan R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接