【问题标题】:R apply multiple functions when large number of categories/types are present using case_when (R vectorization)当使用 case_when(R 向量化)存在大量类别/类型时,R 应用多个函数
【发布时间】:2020-06-14 19:58:49
【问题描述】:

假设我有一个如下形式的数据集:

City=c(1,2,2,1)
Business=c(2,1,1,2)
ExpectedRevenue=c(35,20,15,19)
zz=data.frame(City,Business,ExpectedRevenue)
zz_new=do.call("rbind", replicate(zz, n=30, simplify = FALSE))

我的实际数据集包含大约 200K 行。此外,它还包含 100 多个城市的信息。 假设,对于每个城市(我也称之为“类型”),我有以下需要应用的功能:

#Writing the custom functions for the categories here

Type1=function(full_data,observation){
  NewSet=full_data[which(!full_data$City==observation$City),]
  BusinessMax = max(NewSet$ExpectedRevenue)+10*rnorm(1)
  return(BusinessMax)
}

Type2=function(full_data,observation){
  NewSet=full_data[which(!full_data$City==observation$City),]
  BusinessMax = max(NewSet$ExpectedRevenue)-100*rnorm(1)
  return(BusinessMax)
}

再一次,上面的两个函数是我用来说明的非常简单的函数。这里的想法是,对于每个城市(或“类型”),我需要为数据集中的每一行运行不同的函数。在上述两个函数中,我使用了 rnorm 来检查并确保我们为每一行绘制不同的值。

现在对于整个数据集,我想首先将观察结果划分为不同的城市(或“类型”)。我可以使用 (zz_new[["City"]]==1) [另见下文] 来做到这一点。然后为每个类运行各自的函数。然而,当我运行下面的代码时,我得到了 -Inf

有人能帮我理解为什么会这样吗?

对于示例数据,我希望获得 20 加 10 倍的随机值(对于 Type =1)和 35 减 100 倍的随机值(对于 Type=2)。每行的值也应该不同,因为我是从随机正态分布中绘制它们的。

library(dplyr) #I use dplyr here
zz_new[,"AdjustedRevenue"] = case_when(
  zz_new[["City"]]==1~Type1(full_data=zz_new,observation=zz_new[,]),
  zz_new[["City"]]==2~Type2(full_data=zz_new,observation=zz_new[,])
)

非常感谢。

【问题讨论】:

  • 为了清楚起见,您有 100 个函数,还是有一些规则可以作为 100 个函数的基础?如果函数是可泛化的(例如,对于组i,我们想要rnorm(x, i))如果它有点泛化,那么创建一个函数并使用参数来处理它可能更简单。例如:function(x){if(!is.factor(x))x <- as.factor(x);sims <- rnorm(length(x)); x <- as.integer(x); c(20, -35)[x] + c(10, 100)[x] * sims} 将使用factor 的顺序来获取示例中的结果(假设顺序正确)。当然是 x 是数字,这可能更简单。
  • 不幸的是,我有 100 个不同的功能需要多次运行(10-20K 次)。此处使用的简短函数仅用于说明目的。
  • 这些是如何存储的?基于它应该应用于的值的一些通用名称? (type1 -> city 1, type2 -> city 2, all the way to city N) 还是必须手动输入?
  • 每个类型/城市到类型/城市N的函数都是手动编写的。

标签: r vectorization case-when


【解决方案1】:

让我们看一下您的代码。 我重写你的代码

library(dplyr)
zz_new[,"AdjustedRevenue"] = case_when(
  zz_new[["City"]]==1~Type1(full_data=zz_new,observation=zz_new[,]),
  zz_new[["City"]]==2~Type2(full_data=zz_new,observation=zz_new[,])
)

zz_new %>%
  mutate(AdjustedRevenue = case_when(City == 1 ~ Type1(zz_new,zz_new),
                                     City == 2 ~ Type2(zz_new,zz_new)))

由于您使用的是dplyr,但不要使用此软件包提供的强大工具。

除了mutate 的用法之外,一个关键的变化是我用zz_new 替换了zz_new[,]。现在我们看到Type-functions 的两个参数是相同的数据帧。

下一步:看看你的函数

Type1 <- function(full_data,observation){
  NewSet=full_data[which(!full_data$City==observation$City),]
  BusinessMax = max(NewSet$ExpectedRevenue)+10*rnorm(1)
  return(BusinessMax)
}

Type1(zz_new,zz_new) 调用。所以NewSet的定义给了我们

NewSet=full_data[which(!full_data$City==observation$City),]

# replace the arguments
NewSet <- zz_new[which(!zz_new$City==zz_new$City),]

因此NewSet 始终是一个零行的数据框。将max 应用于data.frame 的空列会产生-Inf

【讨论】:

  • 现在更有意义了。这里只是一个澄清问题。这是因为 Type1 和 Type2 中的子集函数,还是因为我无法正确调用 case_when 中的每一行观察?非常感谢。我本质上想将整个数据集作为第一个参数传递,并将观察的每一行作为第二个参数传递。
  • 请解释您要做什么。我敢打赌,您的问题有一个不复杂的解决方案。 :-)
  • 该函数应将整个数据集作为第一个参数,将单个行作为第二个参数。这些函数在这里所做的是,它获取整个数据集的子集,其中城市/类型与观测的城市/类型不同,获取该子集的最大值,最后添加/减去一些随机数。这有意义吗?再一次,这些函数在这里只是为了说明。当我输入“Type1(zz_new,zz_new[1,])”时,我得到了正确的结果(我验证了这一点)。在这种情况下,它正确地对数据进行子集化,然后取最大值。
猜你喜欢
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-27
相关资源
最近更新 更多