You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从不同长度列随机抽取指定元素的R语言实现问题

问题:从含NA的多列tibble中按指定数量随机抽取非NA物种

数据结构说明

现有一个维度为1042×64的tibble,每一列代表一个两栖动物科,每一行是对应科下的物种名称。除了包含1042个物种的科外,其他列均用NA补全至1042行。前5行2列的数据示例如下:

> amphilist[1:5,1:2]
A tibble: 5 × 2
  `Allophrynidae_(1_genus;_3_species)` `Alsodidae_(3_genera;_26_species)`
  <chr>                                <chr>                              
1 Allophryne_relicta                   Alsodes_australis                 
2 Allophryne_resplendens               Alsodes_barrioi                    
3 Allophryne_ruthveni                  Alsodes_cantillanensis            
4 NA                                   Alsodes_coppingeri                 
5 NA                                   Alsodes_gargola 

已完成的准备工作

已通过循环计算每个科的物种丰富度,并通过条件语句确定了每个科需要抽取的物种数量,代码及结果如下:

amphilist <- read_xlsx("amphilist.xlsx", col_names = TRUE)

families <- colnames(amphilist)
family_n <- ncol(amphilist)
spcR <- vector(length = family_n)

for(i in 1:length(families)) {
  families.i <- families[i]
  spcR[i] <- colSums(amphilist[,families.i] > 0, na.rm = TRUE)
}

species_no <- data.frame(families, spcR)
species_no$choose <- ifelse(species_no$spcR > 50, ceiling(species_no$spcR/10), 
                            ifelse(species_no$spcR >= 5 & species_no$spcR <= 50,
                                   5, species_no$spcR))

> species_no[1:3,]
                                        families spcR choose
1             Allophrynidae_(1_genus;_3_species)    3      3
2               Alsodidae_(3_genera;_26_species)   26      5
3 Alytidae_(2_subfamilies;_3_genera;_12_species)   12      5

当前问题

尝试随机抽取时,结果全为NA,即使无NA的列也出现该问题。错误代码如下:

choose_no <- species_no$choose
set.seed(43)
for(i in 1:length(families)) {
  families.i <- families[i]
  choose_no.i <- choose_no[i]
  rand_amphilist <- amphilist[sample(amphilist[,i], 
                                     size = choose_no.i), ]
}

解决方案

错误原因

原代码中sample(amphilist[,i], size = choose_no.i)是对列中的元素(物种名或NA)进行采样,随后用这些采样得到的字符串作为行索引去提取tibble的行,这完全不符合行索引的规则(行索引应为数字),因此导致结果全为NA。

正确代码1:循环实现

先提取每列的非NA物种,再从中随机抽取指定数量,最后将结果合并并补全NA至1042行:

library(dplyr)

# 初始化结果tibble
rand_amphilist <- tibble()

set.seed(43)
for(i in 1:length(families)) {
  # 获取当前列的所有非NA物种
  current_species <- na.omit(amphilist[[i]])
  # 按指定数量随机抽取
  sampled_species <- sample(current_species, size = choose_no[i], replace = FALSE)
  # 转换为带列名的tibble
  sampled_tbl <- tibble(!!families[i] := sampled_species)
  # 补全NA到1042行(若需要保持原数据行数)
  sampled_tbl <- bind_rows(sampled_tbl, tibble(!!families[i] := rep(NA, 1042 - nrow(sampled_tbl))))
  # 合并到结果中
  rand_amphilist <- if(i == 1) sampled_tbl else bind_cols(rand_amphilist, sampled_tbl)
}

正确代码2:tidyverse函数式实现

用purrr的map2_dfc函数,更简洁地完成批量处理:

library(purrr)
library(dplyr)

set.seed(43)
rand_amphilist <- map2_dfc(amphilist, choose_no, function(col, n) {
  # 提取非NA物种并采样
  sampled <- sample(na.omit(col), size = n, replace = FALSE)
  # 补全NA到1042行并转为带列名的tibble列
  c(sampled, rep(NA, 1042 - length(sampled))) %>%
    as_tibble_col(column_name = colnames(amphilist)[which(colnames(amphilist) == colnames(col))])
})

内容的提问来源于stack exchange,提问作者feprocha93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:40:55