R 一个列表的元素作为作用于另一个列表的函数的参数

R 一个列表的元素作为作用于另一个列表的函数的参数,r,list,lapply,R,List,Lapply,我有一个数据帧列表,其中每个数据帧都是相似的(具有相同名称的相同列),但包含关于不同的相关“事物”(例如,花的种类)的信息。我需要一种优雅的方法,使用函数cut()将所有这些数据帧中的一列从连续重新分类为分类。问题是每个“东西”(花)都有不同的切点,会使用不同的标签 我甚至把切点和标签放在一个单独的列表中。如果我们遵循我的假例子,它基本上是这样的: iris <- iris peony <- iris #pretending that this is actually diffe

我有一个数据帧列表,其中每个数据帧都是相似的(具有相同名称的相同列),但包含关于不同的相关“事物”(例如,花的种类)的信息。我需要一种优雅的方法,使用函数
cut()
将所有这些数据帧中的一列从连续重新分类为分类。问题是每个“东西”(花)都有不同的切点,会使用不同的标签

我甚至把切点和标签放在一个单独的列表中。如果我们遵循我的假例子,它基本上是这样的:

iris <- iris 
peony <- iris  #pretending that this is actually different data!
flowers <- list(iris = iris, peony = peony)

params <- list(iris_param = list(cutpoints = c(1, 4.5),
                             labels = c("low", "medium", "high")),

           peony_param = list(cutpoints = c(1.5, 2.5, 5),
                              labels = c("too_low", "kinda_low", "okay", "just_right")))

#And we want to cut 'Sepal.Width' on both peony and iris

iris我认为现在是
for
循环的好时机。写得简单明了:

for (petal in seq_along(flowers)) {
    flowers[[petal]]$Sepal.Width.Cut = cut(
        x = flowers[[petal]]$Sepal.Width,
        breaks = c(-Inf, params[[petal]]$cutpoints, Inf),
        labels = params[[petal]]$labels
    )
}
注意,(a)我必须增加你的休息时间,以使
cut
对标签的长度感到满意,(b)实际上我只是在重复1,2。更健壮的版本可能会迭代列表的名称,并且作为安全检查,需要
params
列表具有相同的名称。由于列表的名称不同,我只使用了索引


这可能可以使用
mapply
实现。我看不出这样做有什么好处-除非你已经习惯了
mappy
,唯一真正的区别是
mappy
版本的编写时间要长10倍。

我认为这是
for
循环的好时机。写得简单明了:

for (petal in seq_along(flowers)) {
    flowers[[petal]]$Sepal.Width.Cut = cut(
        x = flowers[[petal]]$Sepal.Width,
        breaks = c(-Inf, params[[petal]]$cutpoints, Inf),
        labels = params[[petal]]$labels
    )
}
注意,(a)我必须增加你的休息时间,以使
cut
对标签的长度感到满意,(b)实际上我只是在重复1,2。更健壮的版本可能会迭代列表的名称,并且作为安全检查,需要
params
列表具有相同的名称。由于列表的名称不同,我只使用了索引


这可能可以使用
mapply
实现。我看不出这样做有什么好处-除非你已经习惯了
mappy
,唯一真正的区别是
mappy
版本将花费你10倍的时间来编写。

我喜欢Gregor的解决方案,但我可能会堆叠数据:

library(data.table)

# rearrange parameters
params0 = setNames(params, c("iris", "peony"))
my_params = c(list(.id = names(params0)), do.call(Map, c(list, params0)))

# stack
DT = rbindlist(flowers, id = TRUE)

# merge and make cuts
DT[my_params, Sepal.Width.Cut := 
  cut(Sepal.Width, breaks = c(-Inf,cutpoints[[1]],Inf), labels = labels[[1]])
, on=".id", by=.EACHI]
(我借用了格雷戈对切点的翻译。)结果是:

       .id Sepal.Length Sepal.Width Petal.Length Petal.Width   Species Sepal.Width.Cut
  1:  iris          5.1         3.5          1.4         0.2    setosa       kinda_low
  2:  iris          4.9         3.0          1.4         0.2    setosa       kinda_low
  3:  iris          4.7         3.2          1.3         0.2    setosa       kinda_low
  4:  iris          4.6         3.1          1.5         0.2    setosa       kinda_low
  5:  iris          5.0         3.6          1.4         0.2    setosa       kinda_low
 ---                                                                                  
296: peony          6.7         3.0          5.2         2.3 virginica            okay
297: peony          6.3         2.5          5.0         1.9 virginica       kinda_low
298: peony          6.5         3.0          5.2         2.0 virginica            okay
299: peony          6.2         3.4          5.4         2.3 virginica            okay
300: peony          5.9         3.0          5.1         1.8 virginica            okay
我认为堆叠的数据通常比数据帧列表更有意义。您不需要使用data.table来堆叠或进行切割,但它的设计非常适合这些任务


它是如何工作的

  • 我想,
    rbindlist
    很清楚

  • 代码

    DT[my_params, on = ".id"]
    
    进行合并。要了解这意味着什么,请查看:

    as.data.table(my_params)
    #      .id   cutpoints                            labels
    # 1:  iris     1.0,4.5                   low,medium,high
    # 2: peony 1.5,2.5,5.0 too_low,kinda_low,okay,just_right
    
    因此,我们正在通过公共
    .id
    列将此表与
    DT
    合并

  • 当我们像这样合并时

    DT[my_params, j, on = ".id", by=.EACHI]
    
    这意味着

    • 执行合并,将
      my_params
      的每一行与
      DT
      的相关行匹配
    • 使用两个表中的任一列,对
      my_params
      的每一行执行
      j
  • 在这种情况下,
    j
    的形式是
    column\u for_DT:=cut(…)
    ,它在
    DT
    中创建了一个新列


  • 我喜欢Gregor的解决方案,但我可能会堆叠数据:

    library(data.table)
    
    # rearrange parameters
    params0 = setNames(params, c("iris", "peony"))
    my_params = c(list(.id = names(params0)), do.call(Map, c(list, params0)))
    
    # stack
    DT = rbindlist(flowers, id = TRUE)
    
    # merge and make cuts
    DT[my_params, Sepal.Width.Cut := 
      cut(Sepal.Width, breaks = c(-Inf,cutpoints[[1]],Inf), labels = labels[[1]])
    , on=".id", by=.EACHI]
    
    (我借用了格雷戈对切点的翻译。)结果是:

           .id Sepal.Length Sepal.Width Petal.Length Petal.Width   Species Sepal.Width.Cut
      1:  iris          5.1         3.5          1.4         0.2    setosa       kinda_low
      2:  iris          4.9         3.0          1.4         0.2    setosa       kinda_low
      3:  iris          4.7         3.2          1.3         0.2    setosa       kinda_low
      4:  iris          4.6         3.1          1.5         0.2    setosa       kinda_low
      5:  iris          5.0         3.6          1.4         0.2    setosa       kinda_low
     ---                                                                                  
    296: peony          6.7         3.0          5.2         2.3 virginica            okay
    297: peony          6.3         2.5          5.0         1.9 virginica       kinda_low
    298: peony          6.5         3.0          5.2         2.0 virginica            okay
    299: peony          6.2         3.4          5.4         2.3 virginica            okay
    300: peony          5.9         3.0          5.1         1.8 virginica            okay
    
    我认为堆叠的数据通常比数据帧列表更有意义。您不需要使用data.table来堆叠或进行切割,但它的设计非常适合这些任务


    它是如何工作的

  • 我想,
    rbindlist
    很清楚

  • 代码

    DT[my_params, on = ".id"]
    
    进行合并。要了解这意味着什么,请查看:

    as.data.table(my_params)
    #      .id   cutpoints                            labels
    # 1:  iris     1.0,4.5                   low,medium,high
    # 2: peony 1.5,2.5,5.0 too_low,kinda_low,okay,just_right
    
    因此,我们正在通过公共
    .id
    列将此表与
    DT
    合并

  • 当我们像这样合并时

    DT[my_params, j, on = ".id", by=.EACHI]
    
    这意味着

    • 执行合并,将
      my_params
      的每一行与
      DT
      的相关行匹配
    • 使用两个表中的任一列,对
      my_params
      的每一行执行
      j
  • 在这种情况下,
    j
    的形式是
    column\u for_DT:=cut(…)
    ,它在
    DT
    中创建了一个新列


  • Is
    iris Use
    mappy
    或a
    for
    循环。Is
    iris Use
    mappy
    或a
    for
    循环。我将研究如何使用名称-在我的真实数据中,列表元素的名称是相同的。我一直在避免循环,因为人们似乎讨厌R中的循环,但这是一个非常明确的解决方案。谢谢For循环确实很好,只要您避免其他有时会伴随它们而来的坏习惯(在循环中增加对象,而不是预先分配,可用时不使用矢量化)。我建议阅读。我将研究如何使用这些名称——在我的真实数据中,列表中元素的名称是相同的。我一直在避免循环,因为人们似乎讨厌R中的循环,但这是一个非常明确的解决方案。谢谢For循环确实很好,只要您避免其他有时会伴随它们而来的坏习惯(在循环中增加对象,而不是预先分配,可用时不使用矢量化)。我建议你读书。