
R Script: Random Sampling Workflow for M&E
R Script: Random Sampling Workflow for M&E
Learn how to create a reproducible random sampling workflow in R, from preparing a sampling frame to selecting, checking and exporting a final evaluation sample.
What You Will Learn
By the end of this tutorial, you will be able to:
- Import and check a sampling frame in R.
- Filter the population according to eligibility criteria.
- Generate a reproducible simple random sample.
- Perform stratified random sampling.
- Create a reserve sample for fieldwork.
- Check the selected sample for basic quality issues.
- Export the final sample for fieldwork.
- Document the randomization process.
What You Need
- R installed on your computer.
- A sampling frame in CSV format.
- A clearly defined eligible population.
- A predefined sampling strategy.
- A required sample size.
If you are using R as part of broader quantitative M&E work, you can also explore EvalCommunity’s AI in Monitoring & Evaluation course.
What Is Random Sampling?
Random sampling selects units from a defined population using a randomization procedure rather than personal judgment.
For example, an evaluation team may have 2,500 eligible students but need to survey 300. Instead of selecting participants based on convenience or researcher preference, the team can use a predefined random sampling procedure.
R is useful because the process can be documented and reproduced using the same sampling frame, code and random seed.
Important: R can automate the selection procedure, but it cannot determine whether your sampling design is appropriate. The population, sampling frame, sampling unit, sample size and sampling strategy should be established before running the script.
Step 1: Prepare the Sampling Frame
A sampling frame is the list from which the sample will actually be selected.
A simple CSV file might contain:
participant_id,gender,age,school,region,eligible
001,Female,17,School_A,North,Yes
002,Male,18,School_A,North,Yes
003,Female,16,School_B,South,Yes
004,Male,17,School_B,South,Yes
005,Female,18,School_C,East,YesDepending on the evaluation, the sampling unit could be a person, household, school, health facility, village, project site or organization.
The sampling frame should represent the population you actually intend to study.
Step 2: Install and Load the R Package
The dplyr package provides useful functions for filtering, grouping and sampling data.
install.packages("dplyr")Then load it:
library(dplyr)You only need to install a package once. After installation, load it when starting a new R session.
Step 3: Import the Sampling Frame
Import your CSV file:
sampling_frame <- read.csv("sampling_frame.csv")Check the first records:
head(sampling_frame)Check the number of records:
nrow(sampling_frame)Check the variable names:
names(sampling_frame)Inspect the structure:
str(sampling_frame)Step 4: Filter the Eligible Population
Only records that meet the predefined eligibility criteria should normally enter the sampling process.
eligible_frame <- sampling_frame %>%
filter(eligible == "Yes")Check how many eligible units remain:
nrow(eligible_frame)Document this number. If the original frame contains 2,500 records but only 2,320 are eligible, the sampling population is 2,320.
Step 5: Check for Duplicate IDs
Each sampling unit should normally have a unique identifier.
anyDuplicated(eligible_frame$participant_id)A result of 0 means that R did not identify duplicated IDs.
To identify duplicate records:
eligible_frame %>%
group_by(participant_id) %>%
filter(n() > 1)Resolve duplicate records before selecting the sample.
Step 6: Select a Simple Random Sample
Suppose your evaluation requires 300 participants.
Define the sample size:
sample_size <- 300Set a random seed:
set.seed(12345)The seed makes the randomization reproducible.
Now select the sample:
sample <- eligible_frame %>%
slice_sample(n = sample_size)Check the result:
nrow(sample)The expected result is 300.
Why record the seed? Another researcher can reproduce the selection when using the same data and code.
Step 7: Use Stratified Random Sampling
Simple random sampling may produce an undesirable distribution across important subgroups. If representation across predefined groups matters, stratified sampling may be more appropriate.
For example, suppose an evaluation covers participants from North, South and East regions.
eligible_frame %>%
count(region)Select a Fixed Number From Each Stratum
If the sampling protocol requires 100 participants from each region:
set.seed(12345)
stratified_sample <- eligible_frame %>%
group_by(region) %>%
slice_sample(n = 100) %>%
ungroup()Check the result:
stratified_sample %>%
count(region)This should return 100 selected participants per region, assuming each region contains at least 100 eligible units.
Sampling note: Selecting the same number from strata of different sizes changes the selection probabilities. Depending on the evaluation design, analysis may therefore require sampling weights.
Proportionate Stratified Sampling
If the sample should reflect the population distribution, first calculate the proportion represented by each stratum.
eligible_frame %>%
count(region) %>%
mutate(
proportion = n / sum(n)
)For a target sample of 300, you can calculate an approximate allocation:
allocation <- eligible_frame %>%
count(region) %>%
mutate(
proportion = n / sum(n),
sample_n = round(proportion * 300)
)Review the allocations before implementing the final sample, particularly when rounding means the allocated numbers do not sum exactly to 300.
Step 8: Sample Within Schools or Other Clusters
Some evaluation designs require a fixed number of participants from each school, facility or project site.
For example, to select 20 students from each school:
set.seed(12345)
school_sample <- eligible_frame %>%
group_by(school) %>%
slice_sample(n = 20) %>%
ungroup()Check the number selected from each school:
school_sample %>%
count(school)Sampling within clusters is different from selecting individuals from the entire population. If the evaluation design involves clustering, the analysis should account for that design where appropriate.
Step 9: Generate an Explicit Random Number
Another approach is to assign every eligible participant a random number and then sort the frame.
set.seed(12345)
eligible_frame <- eligible_frame %>%
mutate(random_number = runif(n()))Sort the frame:
randomized_frame <- eligible_frame %>%
arrange(random_number)Select the first 300 records:
sample <- randomized_frame %>%
slice_head(n = 300)Keeping the randomized frame can be useful for documenting the selection process.
Step 10: Create a Reserve Sample
Fieldwork may produce situations where selected participants are unavailable, unreachable or no longer eligible.
If the approved sampling protocol allows replacement, create a reserve sample at the same time as the primary sample.
For example, select 300 primary and 50 reserve participants:
set.seed(12345)
randomized_frame <- eligible_frame %>%
mutate(random_number = runif(n())) %>%
arrange(random_number)
primary_sample <- randomized_frame %>%
slice_head(n = 300)
reserve_sample <- randomized_frame %>%
slice(301:350)Do not replace participants based on convenience. Replacement rules should be defined before fieldwork and should preserve the intended sampling design where applicable.
Step 11: Check the Final Sample
Before sending the sample to the field team, perform basic quality checks.
Check the sample size
nrow(primary_sample)Check for duplicate participants
anyDuplicated(primary_sample$participant_id)Check gender distribution
primary_sample %>%
count(gender)Check regional distribution
primary_sample %>%
count(region)Check school distribution
primary_sample %>%
count(school)These checks identify obvious problems. They do not prove that a sample is statistically representative.
Step 12: Compare the Sample With the Population
Comparing important characteristics between the eligible population and the selected sample can help identify unexpected differences.
For example, calculate the population distribution by gender:
eligible_frame %>%
count(gender) %>%
mutate(
population_share = n / sum(n)
)Then calculate the sample distribution:
primary_sample %>%
count(gender) %>%
mutate(
sample_share = n / sum(n)
)Differences do not automatically indicate an error. Some variation between a population and a random sample is expected.
Step 13: Export the Sample
Export the primary sample:
write.csv(
primary_sample,
"primary_sample.csv",
row.names = FALSE
)Export the reserve sample:
write.csv(
reserve_sample,
"reserve_sample.csv",
row.names = FALSE
)Access to exported sampling files should follow your project’s data protection and confidentiality procedures.
Complete R Random Sampling Script
The following script combines the core steps into one reproducible workflow.
# -----------------------------------------
# RANDOM SAMPLING WORKFLOW FOR M&E
# -----------------------------------------
library(dplyr)
# 1. Import sampling frame
sampling_frame <- read.csv("sampling_frame.csv")
# 2. Keep eligible participants
eligible_frame <- sampling_frame %>%
filter(eligible == "Yes")
# 3. Check for duplicate IDs
if (anyDuplicated(eligible_frame$participant_id) > 0) {
stop("Duplicate participant IDs detected.")
}
# 4. Define sample size
sample_size <- 300
# 5. Set and record random seed
sampling_seed <- 12345
set.seed(sampling_seed)
# 6. Randomly select participants
primary_sample <- eligible_frame %>%
slice_sample(n = sample_size)
# 7. Check sample size
print(nrow(primary_sample))
# 8. Check sample distribution
print(primary_sample %>% count(gender))
print(primary_sample %>% count(region))
# 9. Export sample
write.csv(
primary_sample,
"primary_sample.csv",
row.names = FALSE
)
# 10. Save sampling metadata
metadata <- data.frame(
population_size = nrow(eligible_frame),
sample_size = nrow(primary_sample),
random_seed = sampling_seed
)
write.csv(
metadata,
"sampling_metadata.csv",
row.names = FALSE
)Practical M&E Example
Imagine an evaluation team assessing an education programme implemented in 12 schools. The team has a database containing 2,500 students and needs a sample of 300 students for a survey.
The team first applies the predefined eligibility criteria, checks for duplicate IDs and confirms the size of the eligible population.
If the evaluation design calls for a simple random sample, the team uses slice_sample() after setting a documented random seed.
If the design requires representation across regions or schools, the team uses the appropriate stratified or cluster-based approach instead.
Before fieldwork, the team checks the sample, records the randomization details and exports the final list.
Key principle: The R script implements the sampling methodology. It does not replace the evaluator’s decisions about who should be included, how many participants are needed or which sampling design is appropriate.
How to Verify the Result
Before using the sample for fieldwork, check:
- Does the sampling frame correspond to the intended population?
- Were eligibility criteria applied consistently?
- Are participant IDs unique?
- Does the sample contain the required number of units?
- Was the correct sampling design used?
- Was the random seed recorded?
- Were strata or clusters handled correctly?
- Are replacement rules documented?
- Does the final sample match the evaluation protocol?
- Has the final file been checked before being shared?
Ideally, a second evaluator should be able to inspect the sampling frame, code, seed and documentation and understand how the sample was generated.
Common Mistakes to Avoid
- Using an incomplete sampling frame: Random selection cannot correct for missing members of the target population.
- Ignoring duplicate records: Duplicates can give some units a greater chance of selection.
- Changing the sample after seeing the results: Post-hoc selection can undermine the intended randomization.
- Using convenience replacements: Replacing unavailable participants with whoever is easiest to reach can introduce selection bias.
- Ignoring the sampling design during analysis: Stratification, clustering and unequal selection probabilities can affect analysis.
- Assuming random means representative: Random sampling does not eliminate sampling variation or non-response.
Limitations and Responsible Use
A technically correct R script does not guarantee a statistically appropriate evaluation sample.
Pay particular attention to:
- The completeness and quality of the sampling frame.
- The definition of the target and eligible population.
- The required sample size.
- Stratification and clustering.
- Non-response and attrition.
- Replacement procedures.
- Sampling weights where required.
The sampling methodology should be established before random selection. R should implement that methodology consistently rather than being used to test different approaches until a desirable-looking sample appears.
Using AI With R for Sampling Workflows
AI assistants can help explain, debug or adapt R code, but they should not make unsupported methodological decisions.
For example, you could ask an AI assistant:
Review this R sampling script for coding errors and potential
sampling-design problems.
Do not change the sampling design.
Identify assumptions that I should verify before using
the script for an evaluation.AI can also help explain unfamiliar R functions, identify coding errors or adapt a working script to another dataset.
The evaluator remains responsible for the sampling methodology, assumptions and final decision.
Frequently Asked Questions
What R function is used for random sampling?
With dplyr, slice_sample() provides a straightforward way to randomly select rows from a dataset. It can also be used within groups when implementing an appropriate stratified workflow.
Why should I use set.seed() when sampling in R?
set.seed() makes the random-number sequence reproducible. Recording the seed allows another analyst to reproduce the selection when using the same data and code.
Can R determine my evaluation sample size?
R can perform sample-size calculations, but the required sample size depends on the evaluation design, outcome, precision requirements and statistical assumptions. It should be established as part of the evaluation methodology.
Is a random sample automatically representative?
No. Random sampling provides a probability-based selection mechanism, but the quality of the sampling frame, sample size, non-response and sampling design all affect how well findings can generalize to the target population.
What is stratified random sampling?
Stratified random sampling divides the population into predefined groups and randomly selects units within those groups. It can be useful when the evaluation requires controlled representation across important subgroups.
Should I create a reserve sample?
A reserve sample can be useful when the evaluation protocol permits participant replacement. Replacement rules should be established in advance and should preserve the intended sampling design where applicable.
Key Takeaways
- Start with a clearly defined and appropriate sampling frame.
- Remove ineligible and duplicate records before sampling.
- Use
set.seed()to make random selection reproducible. - Choose the sampling design according to the evaluation methodology.
- Check and document the final sample before fieldwork.
Further EvalCommunity Resources
AI in Monitoring & Evaluation (M&E) Certificate
– practical training on applying AI across M&E workflows.
