我有一个非常复杂的S4对象(来自lavaan模型的输出),其中插槽内的插槽和变量($
)内的插槽位于每个最深插槽的最深层。如何提取和存储此对象中每个元素的object.size
(以及可能的其他函数,如length
和dim
以及对象名称),以便我可以将其与另一个对象进行比较同一个班级?
我已经尝试存储来自str(obj)
和unclass(obj)
的输出,然后操纵输出以提取我想要的信息,但结果却非常繁琐。循环使用名字同样困难。有没有办法将对象“扁平”成列表?是否有任何人可以想到的递归函数反复挖掘每个插槽?
修改
以下是一个示例,使用上面引用的lavaan
包,但理想情况下,解决方案不应该依赖于特定的对象类,并且可以跨类工作:
library(lavaan)
model <- '
# measurement model
ind60 =~ x1 + x2 + x3
dem60 =~ y1 + y2 + y3 + y4
dem65 =~ y5 + y6 + y7 + y8
# regressions
dem60 ~ ind60
dem65 ~ ind60 + dem60
# residual correlations
y1 ~~ y5
y2 ~~ y4 + y6
y3 ~~ y7
y4 ~~ y8
y6 ~~ y8
'
fit <- sem(model, data=PoliticalDemocracy)
对象fit
里面包含许多插槽和对象。当然,我可以从object.size(fit@Data@X[[1]])
等特定元素中提取信息,但我正在寻找一种通用的解决方案。挑战在于我想要提取有关每个元素的相同信息,无论其“深度”如何。
谢谢!
答案 0 :(得分:-1)
似乎purrr
包可能对此有帮助,尤其是flatten
,transpose
,map
/ at_depth
等功能 - 与char矢量结合作为输入您可以轻松地从深层嵌套列表中提取内容。例如,你可以写下&#34;提取器&#34;您需要分离的函数,然后将它们全部存储在列表中,并使用invoke
(也来自purrr
)将您的对象作为唯一的arg或许多此类对象的invoke_map
。
修改强>
以下是一些代码,可帮助您从一个或多个object.size(fit@Data@X[[1]])
对象中提取lavaan
。由于您感兴趣的插槽,实际上很可能在不同的深度,我的猜测是没有简单的通用解决方案。
这个想法是,一旦你知道你感兴趣的确切元素 - 编写一些辅助函数来操作单个/多个这样的对象是相当简单的。我上面提到的功能为实现这一目标提供了友好的捷径
如果我可以提供进一步的帮助,请告诉我。
library("lavaan")
library("tidyverse")
model <- '
# measurement model
ind60 =~ x1 + x2 + x3
dem60 =~ y1 + y2 + y3 + y4
dem65 =~ y5 + y6 + y7 + y8
# regressions
dem60 ~ ind60
dem65 ~ ind60 + dem60
# residual correlations
y1 ~~ y5
y2 ~~ y4 + y6
y3 ~~ y7
y4 ~~ y8
y6 ~~ y8
'
# say you have 3 different models
fit1 <- sem(model, data=PoliticalDemocracy)
fit2 <- sem(model, data=PoliticalDemocracy)
fit3 <- sem(model, data=PoliticalDemocracy)
# S4 objects have function slot() function for accessing so
object.size(fit@Data@X[[1]])
# becomes
slot(slot(fit, "Data"), "X")[[1]]
# since fit is an S4 object - you have to wrap it up
# in a list to manipulate it easier.
# above code becomes :
list(fit1) %>%
map(~ slot(., "Data")) %>%
map(~ slot(., "X")) %>%
flatten %>%
map(object.size)
# wrap up the above code in a helper function ...
extr_obj_size <- function(lavaan_fit) {
list(lavaan_fit) %>%
map(~ slot(., "Data")) %>%
map(~ slot(., "X")) %>%
map(object.size)
}
extr_obj_size(fit1)
# which you can further wrap up in a function that operates
# on a vector of such objects
extr_multiple_obj_size <- function(vec_lavaan_fits) {
vec_lavaan_fits %>%
map(extr_obj_size) %>%
flatten
}
c(fit,fit2,fit3) %>% extr_multiple_obj_size
Edit2
我不知道以下代码对一般有多大帮助,但我混淆了一些东西,假设你知道你感兴趣的插槽名称 - 会检查深度1和2并返回相应的值。
fit <- sem(model, data=PoliticalDemocracy)
slot_of_interest <- "eq.constraints"
# slot names at depth 1
depth1 <- names(getSlots("lavaan"))
# slot names at depth 2
depth2 <- depth1 %>% map(~ slotNames(slot(fit,.)))
# helper fun to check if a slot name of interest is inside a slot
in_slot <- function(x) slot_of_interest %in% x
# so if its at depth 1 - then just map slot()-function with that name
if (slot_of_interest %in% depth1) {
list(fit1) %>% map(~slot(., slot_of_interest))
} else {
# otherwise you would need to detect at which index at depth2 does this name appear
index1 <- depth2 %>% detect_index(in_slot)
# and map first the slot-name at that index - then the corresponding slot of interest
list(fit1) %>% map(~ slot(., depth1[index1])) %>% map(~ slot(., slot_of_interest))
}