【发布时间】:2017-05-20 21:41:03
【问题描述】:
我希望能够对包含类似 S3 列表的对象的数据框(tibble)列应用操作,以作用于列中每个对象的命名项之一。根据问题的底部,我在mutate() 中使用sapply() 进行这项工作,但这似乎是不必要的。
信息存储在包含原子数据的列中,像 mutate() 这样的 dplyr 函数可以按预期工作。这有效,例如:
library(dplyr)
people_cols <- tibble(name = c("Fiona Foo", "Barry Bar", "Basil Baz"),
height_mm = c(1750, 1700, 1800),
weight_kg = c(75, 73, 74)) %>%
mutate(height_inch = height_mm / 25.4)
people_cols
# # A tibble: 3 × 4
# name height_mm weight_kg height_inch
# <chr> <dbl> <dbl> <dbl>
# 1 Fiona Foo 1750 75 68.89764
# 2 Barry Bar 1700 73 66.92913
# 3 Basil Baz 1800 74 70.86614
但我想处理 S3 列表对象中的数据。这是一个玩具示例:
person_stats <- function(name, height_mm, weight_kg) {
this_person <- structure(list(name = name,
height_mm = height_mm,
weight_kg = weight_kg),
class = "person_stats")
}
fiona <- person_stats("Fiona Foo", 1750, 75)
barry <- person_stats("Barry Bar", 1700, 73)
basil <- person_stats("Basil Baz", 1800, 74)
fiona$height_mm
# [1] 1750
我可以像这样将这些对象放入一个 tibble 列中:
people <- tibble(personstat = list(fiona, barry, basil))
people
# # A tibble: 3 × 1
# personstat
# <list>
# 1 <S3: person_stats>
# 2 <S3: person_stats>
# 3 <S3: person_stats>
但是,如果我尝试在包含这些对象的列上使用 mutate(),我会得到错误:
people <- tibble(personstat = list(fiona, barry, basil)) %>%
mutate(height_inch = personstat$height_mm / 25.4)
# Error in mutate_impl(.data, dots) : object 'personstat' not found
尽量保持简单 - 如果我什至可以自己引用已命名的项目,那么我至少可以将它们放入一个新列,然后对它们执行任何操作:
people <- tibble(personstat = list(fiona, barry, basil)) %>%
mutate(height_mm = personstat$height_mm)
# Error in mutate_impl(.data, dots) :
# Unsupported type NILSXP for column "height_mm"
注意不同的错误,这很有趣 - 它不再抱怨找到列,只是在与命名项目斗争。
我可以使用基本函数 cbind() 和 sapply() 以及 [[ 作为函数来让它工作:
people <- tibble(personstat = list(fiona, barry, basil)) %>%
cbind(height_mm = sapply(.$personstat, '[[', name="height_mm"))
people
# personstat height_mm
# 1 Fiona Foo, 1750, 75 1750
# 2 Barry Bar, 1700, 73 1700
# 3 Basil Baz, 1800, 74 1800
虽然这失去了轻率。
class(people)
# [1] "data.frame"
最后,这让我明白了这一点,它有效,但感觉就像使用 sapply() 有点错过了 dplyr mutate() 的要点,我认为它应该在不需要的情况下一直向下工作:
people <- tibble(personstat = list(fiona, barry, basil)) %>%
mutate(height_mm = sapply(.$personstat, '[[', name="height_mm"))
people
# A tibble: 3 x 2
# personstat height_mm
# <list> <dbl>
# 1 <S3: person_stats> 1750
# 2 <S3: person_stats> 1700
# 3 <S3: person_stats> 1800
有没有什么方法可以使用mutate() 来获得上述输出,而不必依赖sapply() 之类的东西?或者,实际上,从存储在 tibble 列中的类似列表的 S3 对象中提取命名值的任何其他明智方法?
【问题讨论】: