从 dplyrivot_wider 操作输出的 R tibble 创建一些字符列和其他列表列。我理解发生这种情况是因为在pivot_wider进程中存在一些重复的names_from组合。列表列还包含 NULL 值,列出标题时结果如下所示:
> head(test)
# A tibble: 6 × 4
SAMPLE_NO SAMPLE_ANALYSIS_NO `SiO2_%_AES` `LOI_%_AES`
<chr> <chr> <list> <list>
1 16821 11456 <chr [1]> <chr [1]>
2 16825 11461 <chr [1]> <NULL>
3 16829 11466 <chr [1]> <chr [1]>
4 16833 11471 <chr [1]> <chr [1]>
5 16836 11477 <chr [1]> <chr [1]>
6 16837 11479 <chr [1]> <chr [1]>
...在 RStudio 中查看时,标题看起来像这样:
这向我表明列表正在使用一些巧妙的过程来节省内存空间,因为在完整的 tibble 中,有数十万行和数千列,就像这里的示例一样。聪明的部分是列表只存储在特定列中找到的所有唯一值,例如在第一个列表列中只有 43 种可能的结果,然后使用这个结构(我不完全理解)来放置如果需要,则在一行中输入正确的值,否则为 NULL
现在我想转换这个 tibble,这样我就有一个没有列表列(仅字符列)的 tibble(或数据框),并且在输出中输出 NA 而不是 NULL。我已经在这个有趣的谜题上闲逛了几个小时,但现在是时候寻求一些帮助了,因为我被难住了。如果您希望提供帮助,示例数据就是这个链接的 RDS 对象。
我建议,从长远来看,修复创建列表列的枢轴/重塑/聚合可能是值得的,但在短期内:
test <- tibble(SAMPLE_NO = 1:6, SAMPLE_ANALYSIS_NO = 11:16, SiO2 = as.list(letters[1:6]), LOI = replace(as.list(LETTERS[1:6]), 2, list(NULL)))
test
# # A tibble: 6 × 4
# SAMPLE_NO SAMPLE_ANALYSIS_NO SiO2 LOI
# <int> <int> <list> <list>
# 1 1 11 <chr [1]> <chr [1]>
# 2 2 12 <chr [1]> <NULL>
# 3 3 13 <chr [1]> <chr [1]>
# 4 4 14 <chr [1]> <chr [1]>
# 5 5 15 <chr [1]> <chr [1]>
# 6 6 16 <chr [1]> <chr [1]>
library(dplyr)
test %>%
mutate(across(c(SiO2, LOI), ~ sapply(.x, function(z) if (length(z)) z[[1]] else NA)))
# # A tibble: 6 × 4
# SAMPLE_NO SAMPLE_ANALYSIS_NO SiO2 LOI
# <int> <int> <chr> <chr>
# 1 1 11 a A
# 2 2 12 b NA
# 3 3 13 c C
# 4 4 14 d D
# 5 5 15 e E
# 6 6 16 f F
这完全依赖于长度为 0 或 1 的列表元素,仅此而已。如果还有更多,
z[[1]]
将默默地丢弃单元格的剩余元素。虽然这并不假设所有元素都是同一类,但如果某些元素不是字符串并且至少有一个是字符串,这将是一个副作用,因为所有元素都将被强制为 character
。