如何搭建带约束条件的权重模拟场景以追踪个体排名(基于R语言)
Got it, let's walk through how to build this simulation in R. You need to test every valid weight combination that fits your constraints, run the share calculation each time, and track how Tom's rank changes. Here's a step-by-step solution:
Your Constraint Recap
First, let's restate your constraints to make sure we cover everything:
- Weight 1 (Phones):
weights[1] >= 0.5 - Weight 2 (Cars):
0.25 <= weights[2] <= 0.35 - Weight 3 (Boxes):
weights[3] <= 0.15 - Weight 4 (Cats):
weights[4] = 0.05(fixed) - Sum of weights 1-4:
weights[1] + weights[2] + weights[3] + weights[4] = 1 - Weight 5 (exponent):
weights[5] >= 0.95(step 0.01)
Step-by-Step Solution Code
1. Set Up Your Base Data
First, define your core data (swap out the sample items dataframe with your full 100-person dataset whenever you're ready):
# Sample item data (replace with your 100-person dataset) items <- data.frame( Names = c("Sarah", "John", "Tom"), Phones = c(1, 2, 1), Cars = c(2, 1, 1), Boxes = c(9, 14, 12), Cats = c(1, 2, 3) )
2. Generate All Valid Weight Combinations
Instead of manually creating each weight set, we'll programmatically generate every combination that meets your rules. Since weights[4] is fixed and the sum of weights 1-4 must equal 1, we can calculate weights[1] directly from weights[2] and weights[3]:
# Generate possible values for weights[2] (Cars) and weights[3] (Boxes) w2_vals <- seq(0.25, 0.35, by = 0.01) # Step 0.01 as requested w3_vals <- seq(0, 0.15, by = 0.01) # Can't be negative, max 0.15 # Create all combinations of w2 and w3 weight_combinations <- expand.grid(w2 = w2_vals, w3 = w3_vals) # Calculate w1 using the sum constraint (w1 = 1 - w2 - w3 - 0.05) weight_combinations$w1 <- 1 - weight_combinations$w2 - weight_combinations$w3 - 0.05 # Filter out combinations where w1 is less than 0.5 (your first constraint) weight_combinations <- weight_combinations[weight_combinations$w1 >= 0.5, ] # Add valid w5 values (>=0.95, step 0.01; assuming max 1, adjust if needed) w5_vals <- seq(0.95, 1, by = 0.01) weight_combinations <- merge(weight_combinations, data.frame(w5 = w5_vals), all = TRUE) # Add fixed w4 = 0.05 and reorder columns to match your weight vector weight_combinations$w4 <- 0.05 weight_combinations <- weight_combinations[, c("w1", "w2", "w3", "w4", "w5")]
3. Run the Simulation & Track Tom's Rank
Now we'll loop through each valid weight set, compute shares for everyone, calculate ranks, and save Tom's results:
# Initialize a dataframe to store simulation results sim_results <- data.frame( w1 = numeric(), w2 = numeric(), w3 = numeric(), w4 = numeric(), w5 = numeric(), tom_share = numeric(), tom_rank = integer(), stringsAsFactors = FALSE ) # Loop through each weight combination for (i in 1:nrow(weight_combinations)) { # Get current weight vector current_weights <- as.numeric(weight_combinations[i, ]) # Calculate shares using your formula current_shares <- data.frame( Names = items$Names, Shares = round( (current_weights[1]*items$Phones + current_weights[2]*items$Cars + current_weights[3]*items$Boxes + current_weights[4]*items$Cats)^current_weights[5], 3 ) ) # Calculate ranks (descending order: higher share = better rank) # Use ties.method = "min" to handle tied shares (adjust if needed) current_shares$Rank <- rank(-current_shares$Shares, ties.method = "min") # Extract Tom's data from this run tom_data <- current_shares[current_shares$Names == "Tom", ] # Add to results dataframe sim_results[i, ] <- c( current_weights, tom_data$Shares, tom_data$Rank ) }
4. Explore Your Results
Once the simulation finishes, you can analyze Tom's rank across all scenarios. Here are a few useful commands:
# See how often Tom got each rank table(sim_results$tom_rank) # Filter runs where Tom was ranked #1 top_tom_runs <- sim_results[sim_results$tom_rank == 1, ] # View a sample of the weight sets that gave Tom the top rank head(top_tom_runs) # Sort results by Tom's rank to find the best/worst scenarios for him sim_results_sorted <- sim_results[order(sim_results$tom_rank), ] head(sim_results_sorted)
Quick Notes
- If you're using 100 people instead of the sample 3, this code will still work perfectly—we're operating on the entire
itemsdataframe every time. - If you need to adjust the tie-breaking method for ranks, change the
ties.methodargument in therank()function (options include "max", "first", "average", etc.). - For larger constraint ranges or smaller step sizes, you could optimize the loop with vectorized operations, but for your current constraints, the loop is fast enough.
内容的提问来源于stack exchange,提问作者Matt Dietz

