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

R语言中基于条件的数值向量随机分配问题

问题:R语言按条件随机分配数值时,同一条件下所有行取值相同

我正在用虚构值生成模拟数据集,需要在R语言中根据条件为特定行随机分配数值。但当前编写的脚本仅为每个条件返回一个样本值,无法实现让符合条件的所有行按设定概率随机分配所有样本值的需求。

尝试的两种代码实现

代码尝试1

library(dplyr)
set.seed(123) 

patient_data$strength <- NA

patient_data1 <- patient_data %>%
  mutate(
    strength = case_when(
      medication_name == "morphine" & frequency == "1-2" ~ as.character(sample(c(10, 30, 100, 200), 1, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "codeine" & frequency == "1-2" ~ as.character(sample(c(60, 90, 120), 1, prob = c(1/3, 1/3, 1/3))),
      medication_name == "oxycodone" & frequency == "1-2" ~ as.character(sample(c(20, 40, 80, 120), 1, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "oxycodone" & frequency == "4-6" ~ as.character(sample(c(5, 10, 20), 1, prob = c(1/3, 1/3, 1/3))),
      medication_name == "tramadol" & frequency == "4-6" ~ as.character((50)),
      medication_name == "tramadol" & frequency == "1-2" ~ as.character(sample(c(75, 150, 300, 400), 1, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "fentanyl" & frequency == "1-4" ~ as.character((200)),
      medication_name == "fentanyl" & frequency %in% c("1", "2") ~ as.character(sample(c(25, 50, 75, 100), 1, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "buprenorphine" & frequency %in% c("1", "2") ~ as.character(sample(c(5, 10, 20), 1, prob = c(1/3, 1/3, 1/3))),
      medication_name %in% c("morphine", "codeine") & frequency == "4-6" ~ as.character(sample(c(15, 30), 1, prob = c(0.5, 0.5))),
      TRUE ~ NA_character_
    )
  )

print(patient_data1)

代码尝试2

set.seed(123)

patient_data$strength <- NA

patient_data2 <- patient_data %>%
  mutate(
    strength = ifelse(medication_name == "morphine" & frequency == "1-2",
      sample(c(10, 30, 100, 200), size = 1),
      ifelse(medication_name == "morphine" & frequency == "4-6",
      sample(c(15, 30), size = 1),
      ifelse(medication_name == "codeine" & frequency == "1-2",
      sample(c(60, 90, 120), size = 1),
      ifelse(medication_name == "codeine" & frequency == "4-6",
      sample(c(15, 30), size = 1),
      ifelse(medication_name == "oxycodone" & frequency == "1-2",
      sample(c(20, 40, 80, 120), size = 1),
      ifelse(medication_name == "oxycodone" & frequency == "4-6",
      sample(c(5, 10, 20), size = 1),
      ifelse(medication_name == "tramadol" & frequency == "1-2",
      sample(c(75, 150, 300, 400), size = 1),
      ifelse(medication_name == "tramadol" & frequency == "4-6", 50,
      ifelse(medication_name == "fentanyl" & frequency == "1-4", 200,
      ifelse(medication_name == "fentanyl" & (frequency == "1" | frequency == "2"),
      sample(c(25, 50, 75, 100), size = 1),
      ifelse(medication_name == "buprenorphine" & (frequency == "1" | frequency == "2"),
      sample(c(5, 10, 20), size = 1), NA
      ))))
  )))))
)))

print(patient_data2) 

初始数据框

patient_data <- read.table(text="medication_name   frequency   strength
codeine            4-6          NA      
codeine            4-6          NA      
morphine           1-2          NA      
morphine           1-2          NA      
codeine            4-6          NA      
fentanyl           1-4          NA      
morphine           1-2          NA      
morphine           1-2          NA      
morphine           1-2          NA      
oxycodone          4-6          NA", header=T)

当前输出结果

medication_name    frequency    strength
codeine             4-6           30        
codeine             4-6           30        
morphine            1-2           10        
morphine            1-2           10        
codeine             4-6           30        
fentanyl            1-4           200       
morphine            1-2           10        
morphine            1-2           10        
morphine            1-2           10        
oxycodone           4-6           20

期望的输出分布

分布1(匹配设定的样本值分布)

patient_data1$strength  n    percent
                    100 78 0.46706587
                     15 37 0.22155689
                     20  3 0.01796407
                    200 12 0.07185629
                      5 24 0.14371257
                     50 13 0.07784431

分布2(匹配设定的样本值分布)

patient_data2$strength  n    percent
                     10 81 0.48502994
                     20 24 0.14371257
                     25  5 0.02994012
                     30 37 0.22155689
                     50  8 0.04790419
                    200 12 0.07185629

问题原因与解决方案

问题根源

两种尝试的代码中,每个条件分支的sample()函数都只指定了size=1,这会生成单个随机值,然后被广播到所有符合该条件的行,导致同一条件下所有行的strength取值完全相同。

解决方法

核心思路是为每个符合条件的行生成独立的随机样本,也就是让sample()生成和当前条件下行数一致的样本数量。可以通过dplyr的分组(group_by)结合n()获取当前组的行数来实现:

library(dplyr)
set.seed(123)

patient_data_final <- patient_data %>%
  # 按药物名称和频率分组,确保同一条件的行在同一组
  group_by(medication_name, frequency) %>%
  mutate(
    strength = case_when(
      medication_name == "morphine" & frequency == "1-2" ~ as.character(sample(c(10, 30, 100, 200), size = n(), replace = TRUE, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "codeine" & frequency == "1-2" ~ as.character(sample(c(60, 90, 120), size = n(), replace = TRUE, prob = c(1/3, 1/3, 1/3))),
      medication_name == "oxycodone" & frequency == "1-2" ~ as.character(sample(c(20, 40, 80, 120), size = n(), replace = TRUE, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "oxycodone" & frequency == "4-6" ~ as.character(sample(c(5, 10, 20), size = n(), replace = TRUE, prob = c(1/3, 1/3, 1/3))),
      medication_name == "tramadol" & frequency == "4-6" ~ as.character(50),
      medication_name == "tramadol" & frequency == "1-2" ~ as.character(sample(c(75, 150, 300, 400), size = n(), replace = TRUE, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "fentanyl" & frequency == "1-4" ~ as.character(200),
      medication_name == "fentanyl" & frequency %in% c("1", "2") ~ as.character(sample(c(25, 50, 75, 100), size = n(), replace = TRUE, prob = c(0.25, 0.25, 0.25, 0.25))),
      medication_name == "buprenorphine" & frequency %in% c("1", "2") ~ as.character(sample(c(5, 10, 20), size = n(), replace = TRUE, prob = c(1/3, 1/3, 1/3))),
      medication_name %in% c("morphine", "codeine") & frequency == "4-6" ~ as.character(sample(c(15, 30), size = n(), replace = TRUE, prob = c(0.5, 0.5))),
      TRUE ~ NA_character_
    )
  ) %>%
  # 取消分组,恢复正常数据框结构
  ungroup()

print(patient_data_final)

代码说明

  1. group_by(medication_name, frequency):将数据按药物名称和频率分组,确保同一条件的行被归为一组。
  2. sample(..., size = n()):n()会返回当前组的行数,让sample()生成对应数量的随机样本,每个行对应一个独立值。
  3. replace = TRUE:允许重复抽取样本,符合模拟数据的常见需求(如果不需要重复可以去掉,但通常模拟时需要)。

运行这段代码后,同一条件下的行将按设定的概率随机分配不同的数值,符合期望的分布要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:11:59