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