如何按国家分组生成和为1的随机ratio变量?
Hey there, I've got you covered! The trick to creating a ratio variable that sums to 1 per country group (with each value between 0 and 1) is to generate random values for each group, then normalize them by their group total. Here are two straightforward methods using the packages you're already working with (dplyr and data.table):
Method 1: Using dplyr
Since you're already using dplyr for grouping, this fits right into your existing workflow:
# Add the ratio variable, grouped by country DT <- DT %>% group_by(country) %>% mutate( # Generate random positive values for each row in the group temp = runif(n(), min = 0, max = 1), # Normalize by group sum to get ratios that add up to 1 ratio = temp / sum(temp) ) %>% # Optional: Remove the temporary temp variable select(-temp) %>% ungroup()
How it works:
runif(n(), 0, 1)creates a random number between 0 and 1 for every row in the country group.- Dividing each value by the group's total sum ensures the ratios for each country add exactly to 1, and each individual ratio stays between 0 and 1.
Method 2: Using data.table (Faster for Large Datasets)
If you prefer sticking with data.table for efficiency (especially if your dataset grows larger), here's the equivalent code:
# Add ratio using data.table's grouped operations DT[, c("temp", "ratio") := { temp_vals <- runif(.N, 0, 1) list(temp_vals, temp_vals / sum(temp_vals)) }, by = country] # Optional: Delete the temporary temp column DT[, temp := NULL]
Customizing the Distribution
If you don't want completely uniform random ratios, you can use the Beta distribution to control how spread out the ratios are. For example, to get ratios more concentrated around 0.5 (less extreme values), use rbeta():
# Using Beta distribution for more centered ratios (dplyr example) DT <- DT %>% group_by(country) %>% mutate( temp = rbeta(n(), shape1 = 2, shape2 = 2), # Shape params control distribution ratio = temp / sum(temp) ) %>% select(-temp) %>% ungroup()
Verify the Result
To make sure everything works, check that each country's ratio sum equals 1:
DT %>% group_by(country) %>% summarise(total_ratio = sum(ratio)) %>% print()
You might see tiny floating-point errors (like 1.0000000000000002), but that's normal and negligible for practical purposes.
内容的提问来源于stack exchange,提问作者Tom

