矩阵乘法后展开Tibble遇问题:unnest未达预期结果
问题描述
想要计算两个向量的矩阵乘积,示例代码如下:
a <- tibble(n=c("A", "B"), y=c(10,20)) b <- tibble(x=c(5, 15)) res <- a %>% mutate(rotated = map2(y, b, ~ .x %*% .y)) %>% unnest(rotated)
执行后看似正常,但预期unnest后得到2×4的tibble,实际却是2×3的结构:
n y rotated[,1] [,2] <chr> <dbl> <dbl> <dbl> 1 A 10 50 150 2 B 20 100 300
查看res$rotated时还会报错:
Error in if (nchar(current) > nchars) { : missing value where TRUE/FALSE needed
尝试使用bind_cols的方案也无法解决问题。
解决方案
问题根源
map2(y, b, ~ .x %*% .y)中,b是完整tibble而非向量,map2会将整个tibble作为单个元素传入.y,导致每次计算得到1×2的矩阵,而非预期的拆分后的值;unnest处理矩阵列时,会直接将矩阵的列展开为数据框列,同时原rotated列会被移除,这就是访问res$rotated报错的原因——该列已不存在。
修正代码
方案1:提取向量+转换矩阵为tibble
先提取b中的向量,计算后将矩阵转为tibble,确保unnest能正确展开为单独列:
library(tidyverse) a <- tibble(n=c("A", "B"), y=c(10,20)) b <- tibble(x=c(5, 15)) # 提取b的x向量 b_vec <- pull(b, x) res <- a %>% mutate(rotated = map(y, ~ as_tibble(t(.x %*% b_vec)))) %>% unnest(rotated) # 可选:重命名列使其更直观 res <- res %>% rename(rot1 = V1, rot2 = V2)
执行后得到预期的2×4结构:
n y rot1 rot2 <chr> <dbl> <dbl> <dbl> 1 A 10 50 150 2 B 20 100 300
方案2:直接向量化计算(更高效)
如果仅需标量与向量的矩阵乘法,可跳过map直接用向量化操作:
res <- a %>% mutate( rot1 = y * b_vec[1], rot2 = y * b_vec[2] )
结果与方案1完全一致,且代码更简洁高效。
关于访问res$rotated报错的说明
unnest(rotated)执行后,原rotated列已被拆解为对应矩阵列(方案1中是V1、V2),res中不再存在名为rotated的列,因此访问res$rotated会触发错误。可通过colnames(res)查看当前所有列名确认。
内容的提问来源于stack exchange,提问作者MPB_2022
相关产品推荐
相关产品推荐

