【问题标题】:apply with subset function (or custom function based on subset)应用子集函数(或基于子集的自定义函数)
【发布时间】:2017-10-31 22:05:38
【问题描述】:

我正在尝试找到一种方法来使用apply 函数和subset(或基于subset 的自定义函数)。我知道已经问过类似的问题,我的更具体一点。我需要根据多个变量对多个数据集的某些部分进行子集化。我有几种“类型”的数据帧结构,其中一种看起来类似于:

colour  shade   value
RED LIGHT   -1.05
RED LIGHT   -1.37
RED LIGHT   -0.32
RED LIGHT   0.87
RED LIGHT   -0.2
RED DARK    0.52
RED DARK    -0.2
RED DARK    0.64
RED DARK    1.12
RED DARK    4
BLUE    LIGHT   0.93
BLUE    LIGHT   0.78
BLUE    LIGHT   -1.84
BLUE    LIGHT   -0.5
BLUE    LIGHT   -1.11
BLUE    DARK    -4.86
BLUE    DARK    1.11
BLUE    DARK    0.14
BLUE    DARK    0.12
BLUE    DARK    -1.65
GREEN   LIGHT     3.13
GREEN   LIGHT   2.65
GREEN   LIGHT   -2.36
GREEN   LIGHT   -3.11
GREEN   LIGHT   3.49
GREEN   DARK    1.91
GREEN   DARK    -1.1
GREEN   DARK    -1.93
GREEN   DARK    1
GREEN   DARK    -0.23

我有很多。他们的名字存储在

list.dfs.names=df1,df2,df3

基于此我需要使用subset 或基于它的自定义函数:

customSubset=function(df,col,shade){subset(df,df$colour %in% col & df$shade %in% shade)}

我使用这样的自定义函数,因为正如我所说,我有几种类型的 df 结构,它可以加快我的工作速度。它的工作原理是这样的:

example=customSubset(df1,"BLUE","DARK")

输出是:

   colour shade value
11   BLUE LIGHT  0.93
12   BLUE LIGHT  0.78
13   BLUE LIGHT -1.84
14   BLUE LIGHT -0.50
15   BLUE LIGHT -1.11
16   BLUE  DARK -4.86
17   BLUE  DARK  1.11
18   BLUE  DARK  0.14
19   BLUE  DARK  0.12
20   BLUE  DARK -1.65

到目前为止,我一直在使用for 循环,但我想将我的方法更改为apply,这似乎更方便,尤其是在需要嵌套循环的情况下。所以我累了:

lapply(customSubset(list.dfs.names, "BLUE","DARK") )

lapply(list.dfs.names, customSubset("BLUE","DARK") )

没有成功。谁能帮我解决这个问题,我想我不清楚apply 循环是如何工作的。但是,我对for 方法非常熟悉,因此我们将不胜感激任何关于差异的额外解释。

如果无法使用customSubset,我可以使用常规的subset 或任何其他产生与上述example 相同结果的方法。

提前谢谢你

编辑:这是生成与我发布的示例类似的 df 的代码:

`data.frame("colour"=(c(rep("RED",10),rep("BLUE",10),rep("GREEN",10)))
           ,"shade"=c(rep(c(rep("LIGHT",5),rep("DARK",5)),3))
           , runif(30,min=0,max=1))`

EDIT2:根据要求,我正在编辑我的帖子以扩展我的year 问题。我的 dfs 来自不同的年份(每个年份有多个),例如:df.1.2012df.2.2012df.1.2011 等等。主要问题是我永远不需要在所有 dfs 中引用同一年(那样会很容易),而是我需要根据特定范围对数据进行子集化(例如:year+2year-1)。我曾经创建所需年份的列表(例如year+2,它将是list.year=c(2014,2014,2013)),它与我的dfs列表配对(它如何与for loop一起工作)。

我需要为apply 方法找到类似的方法。这是一个例子:

set.seed(200)

 df_2014=data.frame(colour=(c(rep("RED",10),rep("BLUE",10),rep("GREEN",10)))
           ,shade=c(rep(c(rep("LIGHT",5),rep("DARK",5)),3))
           ,year=c(rep(2011:2015,6))
           ,value=runif(30,min=0,max=1))

 df_2013=data.frame(colour=(c(rep("RED",10),rep("BLUE",10),rep("GREEN",10)))
           ,shade=c(rep(c(rep("LIGHT",5),rep("DARK",5)),3))
           ,year=c(rep(2011:2015,6))
           ,value=runif(30,min=0,max=1))
horizon=+1

subset(df_2014, df_2014$colour %in% "BLUE" & df_2014$shade %in% "DARK" & df_2014$year %in% c(2014+horizon))
subset(df_2013, df_2013$colour %in% "BLUE" & df_2013$shade %in% "DARK" & df_2013$year %in% c(2013+horizon))

所以我添加了带有年份的列,并将其命名为year,并在年份之后命名为 dfs(所以year+1 将在这里2014+1)。地平线是不言自明的。结果是:

#df_2014
      colour shade year   value
 20   BLUE  DARK 2015 0.6463296

#df_2013

   colour shade year     value
20   BLUE  DARK 2015 0.6532767

我需要使用apply 函数来列出数据帧(在此编辑中list.df=list(df_2014,df_2013) 与前面的示例一样,但这次添加子集条件year+horizon(并且可能将所有结果放在一个df 中,但这不是这里的主要问题)。

结论:当您在year+horizon 的这一部分中查看我的subset 函数时,year 必须根据循环中引用的 df(from list) 进行更改(而horizon 是恒定的) .

如果您无法理解我的意思,请告诉我,我试图非常具体。

【问题讨论】:

  • 将所有数据框放在一个列表中,使用lapply(list, function(x) {return(customSubset(x, "BLUE","DARK"))})
  • 它返回给我错误:Error: $ operator is invalid for atomic vectors 。我做错了什么?
  • 假设 df1 是发布在 OP 中的 data.frame,而 df2 是类似的 data.frame :lapply(list(df1, df2), function(x) {return(customSubset(x, "BLUE","DARK"))}) 应该可以工作。
  • dplyr::filterpurrr::map 也可以试试!

标签: r


【解决方案1】:

问题似乎是构造

subset(df,df$colour %in% col & df$shade %in% shade)

您正在使用subset,它在其第一个参数df 的环境中评估逻辑表达式,然后执行df$shade %in% shade。这等效于shade %in% shade,因为df 是第一个参数。你应该重写函数如下,使用不同的名字就可以了。

customSubset <- function(DF, COL, SHADE){
    subset(DF, colour %in% COL & shade %in% SHADE)
}

现在一切正常。

set.seed(5601)    # make the results reproducible

df1 <- data.frame(colour = sample(c("RED", "GREEN", "BLUE"), 30, TRUE),
                  shade = sample(c("LIGHT", "DARK"), 30, TRUE),
                  value = rnorm(30, sd = 9))
df2 <- data.frame(colour = c(rep("RED",10), rep("BLUE",10), rep("GREEN",10))
           ,shade=c(rep(c(rep("LIGHT",5),rep("DARK",5)), 3))
           , value = runif(30,min=0,max=1))

list.dfs <- list(df1, df2)

customSubset(df1,"BLUE","DARK")
#   colour shade      value
#5    BLUE  DARK   4.288107
#6    BLUE  DARK   2.860724
#8    BLUE  DARK -10.720379
#10   BLUE  DARK -15.407090
#14   BLUE  DARK  -2.259848
#30   BLUE  DARK -18.364494

# apply the function to all df's in the list
# both forms are equivalent
lapply(list.dfs, function(x) customSubset(x, "BLUE", "DARK"))
lapply(list.dfs, customSubset, "BLUE", "DARK")

【讨论】:

  • 非常感谢您完美运行,但是在将其应用于我的原始代码时我遇到了一个简单的问题:变量之一是数字(更具体的年份)。所以我用你的一个代码lapply(list.dfs, customSubset, "BLUE", "DARK", list.year[i]) 尝试了这样的list.year=c(2015,2015,2016,2016)(四个dfs)。我以类似于for 方法的方式使用[i],这意味着我为每个df 和子集数据分配年份(或多年)。这如何与apply 方法一起使用?
  • 现在问题不同了,函数customSubset 会有一个额外的参数year。您能否编辑问题并给我们一个预期输出的示例?
  • 我编辑了我的帖子。如果有不清楚的地方请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 2021-11-17
  • 2023-04-11
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多