A simple approach that may work for others with similar problems is to look at a large number of subsets and save the best matches. You'll need to define what "better" means since you have two objectives (mean & std). In this example, I gave equal weight to variations from either target. You probably would want to play with different subsample sizes to find a large N that still has a close enough mean and std. You'll also want to repeat your analysis with different subsamples to make sure your results are robust.
# Parameters
target_mean = 1
target_std = .5
subsample_size=15
num_subsamples_to_keep = 5
num_subsamples_to_try = 10000
# This scoring metric is kind of arbitrary and could be tuned.
# For this one, I'm giving equal penalty to deviations from the target mean and the
# target standard deviation. If fitting the target mean was twice as important as
# fitting the target std, you could use:
# return(2*abs(mean-target_mean) + abs(std-target_std))
# Lower scores are better than higher scores. If you redefined the scoring function
# to make high scores better, then you would need to do a reverse sort in the for loop below.
calculate_score <- function(mean, target_mean, std, target_std) {
return(abs(mean-target_mean) + abs(std-target_std))
}
# Make up some data. This will have a different distribution than what we are looking for.
df = data.frame(x=rnorm(100), y=rnorm(100))
# The matrix saved_subsamples will stores the best subsamples, but it will start off blank.
# A corresponding dataframe below will store the scores (subsample_metrics).
# We'll keep saved_subsamples and subsample_metrics synchronized so that row 1 in one
# always corresponds to row 1 of the other.
saved_subsamples = matrix(nrow=num_subsamples_to_keep, ncol=subsample_size)
# Store the metrics of a subsample's quality in this data frame.
# We'll keep the rows of this synchronized with saved_subsamples and
# keep them both sorted so the worst saved subsample is always in the last row
# When we find a new subsample that's better than the worst known, we'll save
# it and resort the matrix and dataframe.
subsample_metrics = data.frame(mean=matrix(NaN, nrow=num_subsamples_to_keep), std=matrix(NaN, nrow=num_subsamples_to_keep), score=matrix(NaN, nrow=num_subsamples_to_keep))
# Try a bunch of different subsamples and keep the best ones
for (attempt in 1:num_subsamples_to_try) {
# Pick a new subsample and evaluate it.
subsample = sample(nrow(df),size=subsample_size)
subsample_mean = mean(df[subsample,'x'])
subsample_std = sd(df[subsample,'x'])
subsample_score = calculate_score(subsample_mean, target_mean, subsample_std, target_std)
# If we don't have any subsamples yet (worst score is NA), or if this new
# subsample is better than our worst saved subsample, then overwrite our
# worst subsample from the end and re-order the lists.
if( is.na(subsample_metrics[nrow(subsample_metrics),'score']) ||
subsample_score < subsample_metrics[nrow(subsample_metrics),'score'] ) {
# Overwrite the worst saved subsample (row 1)
subsample_metrics[nrow(subsample_metrics),'mean'] = subsample_mean
subsample_metrics[nrow(subsample_metrics),'std'] = subsample_std
subsample_metrics[nrow(subsample_metrics),'score'] = subsample_score
# Transpose the subsample so it fits in one row instead of one column
saved_subsamples[nrow(saved_subsamples),] = t(subsample)
# Reorder the saved subsamples (and corresponding metrics) so the worst
# scores (the largest) are at the bottom of the list.
new_order = order(subsample_metrics$score)
saved_subsamples = saved_subsamples[new_order,]
subsample_metrics = subsample_metrics[new_order,]
}
}
# Look at the top subsamples found & their scores
print(subsample_metrics)
print(saved_subsamples)
# Retrieve the top-scoring subsample from the end of the list
top_subsample_indexes = saved_subsamples[1,]
# Use that to subsample the original dataset
top_subsample = df[top_subsample_indexes,]