amt包unnest嵌套轨迹后生成NULL类列表对象的问题排查
嵌套轨迹处理中unnest异常的原因及解决办法
问题重现
以下是可复现问题的完整代码及异常结果:
生成数据集
library(random) test_df <- data.frame(id = rep(c("A", "B", "C"), each = 100), lon = runif(min = -9, max = -6, n = 300), lat = runif(min = 51, max = 55, n = 300), covar1 = runif(min = 0, max = 100, n = 300), covar2 = c(randomStrings(n=300, len=3, unique = F, upperalpha = T, loweralpha = F, digits = F)))
创建嵌套轨迹
test_tracks <- test_df %>% make_track(lon, lat, all_cols = T, crs = 4326, check_duplicates = FALSE, verbose = TRUE) %>% nest(data = c(-id))
计算步长
test_tracks2 <- test_tracks %>% mutate(sl = map(data, step_lengths))
此时生成的嵌套数据框新增列表列sl:
> str(test_tracks2, 2) nested_track [3 × 3] (S3: nested_track/tbl_df/tbl/data.frame) $ id : chr [1:3] "A" "B" "C" $ data:List of 3 $ sl :List of 3
执行unnest操作后的异常
test_tracks3 <- test_tracks2 %>% unnest(cols = c(data, sl))
得到的对象类为NULL,但内部是正常的列表结构:
> class(test_tracks3) [1] "NULL" > str(test_tracks3) List of 6 $ id : chr [1:300] "A" "A" "A" "A" ... $ x_ : num [1:300] -7.67 -7.96 -8.39 -7.26 -8.49 ... $ y_ : num [1:300] 54.3 53.6 54.8 51.9 52.2 ... $ covar1: num [1:300] 55.028 0.772 76.037 64.362 34.512 ... $ covar2: chr [1:300] "KRU" "RJL" "RVG" "BUW" ... $ sl : num [1:300] 0.718 1.28 3.087 1.261 0.648 ... - attr(*, "class")= chr "NULL" - attr(*, "row.names")= int [1:300] 1 2 3 4 5 6 7 8 9 10 ...
用do.call(cbind, ...)转换后变量全变为字符型:
x <- as.data.frame(do.call(cbind, test_tracks3)) > str(x) 'data.frame': 300 obs. of 6 variables: $ id : chr "A" "A" "A" "A" ... $ x_ : chr "-7.67035690904595" "-7.96027435711585" "-8.38539077946916" "-7.25699410191737" ... $ y_ : chr "54.2703927513212" "53.6132442755625" "54.8205336350948" "51.9466292150319" ... $ covar1: chr "55.0277820788324" "0.772069441154599" "76.0366528760642" "64.3617564812303" ... $ covar2: chr "KRU" "RJL" "RVG" "BUW" ... $ sl : chr "0.718259177377767" "1.27994983112401" "3.08749181012144" "1.26120128657495" ...
问题原因
- 自定义类兼容性问题:
test_tracks是amt包的nested_track类(继承自tibble),tidyr的unnest函数在处理这类自定义S3类时,可能出现对象类属性被错误设置为NULL的情况,但内部数据结构是完整的。 do.call(cbind)的类型转换问题:cbind在合并不同类型的向量时,会统一转换为字符矩阵,再转成数据框就会保留字符型,导致原始数值类型丢失。
解决办法
方法一:嵌套状态下直接合并(推荐)
无需执行unnest,直接在嵌套层将sl列合并到每个data对应的轨迹数据框中,避免类兼容性问题:
library(dplyr) library(purrr) library(amt) test_tracks_fixed <- test_tracks2 %>% # 同时遍历data和sl,将sl添加到每个嵌套数据框 mutate(data = map2(data, sl, ~ mutate(.x, sl = .y))) %>% # 移除单独的sl列 select(-sl) # 验证结果:嵌套数据框的data列已包含sl,且类型保留 str(test_tracks_fixed$data[[1]], 2)
方法二:修复unnest后的异常对象
如果已经执行了unnest,直接用as_tibble或as.data.frame转换,无需使用do.call(cbind),这两个函数能识别列表的结构并保留原始变量类型:
# 转换为tibble(推荐,保留tidyverse风格) test_tracks3_fixed <- as_tibble(test_tracks3) str(test_tracks3_fixed) # 或者转换为普通data.frame test_tracks3_df <- as.data.frame(test_tracks3, stringsAsFactors = FALSE) str(test_tracks3_df)
内容的提问来源于stack exchange,提问作者Virginia Morera Pujol
相关产品推荐
相关产品推荐

