Here is one recipe, in case you can live with Spearman
rank correlation. (Which you should: linear correlation
is often not appropriate in the non-normal case. And in
the normal case, there is almost no difference between
the two correlation types.)
Generate samples of your $k$ features with all the
desired attributes. These samples may be random or
historical data. The samples need not have the same
size.
Suppose you want to generate $n$ scenarios. Then
generate $n$ $k$-dimensional normals with the
desired correlation (i.e. a matrix of size $n$ times
$k$). Here you may use Cholesky. (Strictly speaking,
you would need to modify the correlations into
$2\sin(\rho\pi/6)$. But this correction is so tiny
that you may as well leave it out.)
Feed these correlated normal variates into the normal distribution function. The result will be $n$ vectors of uniforms which have the same rank
correlation as the normals (because the distribution
function is monotonically increasing).
Feed these uniforms into the inverses of the
empirical distribution functions of your samples
from step 1. (This is easy: for a uniform variate
$u$, sort a given feature sample, and then pick
element at position
ceiling(u*length(feature_sample))
.) Because the
inverses are non-decreasing, the rank correlation
will remain.
In case you use R
: This whole procedure is implemented in the
function resampleC
in package NMOF
(which I maintain).
Here is an example.
library("NMOF")
gdp <- runif(10000, min = 2, max = 3.5)
une <- runif(10000, min = 4.4, max = 5.1)
dji <- runif(10000, min = 22000, max = 24000)
cor <- array(c(1.0, 0.5, 0.3,
0.5, 1.0, 0.9,
0.3, 0.9, 1.0), dim = c(3,3))
smp <- resampleC(gdp, une, dji, cormat = cor, size = 1000)
cor(smp)
## var1 var2 var3
## var1 1.0000000 0.5140693 0.3041248
## var2 0.5140693 1.0000000 0.9012560
## var3 0.3041248 0.9012560 1.0000000
We can check the ranges.
apply(smp, 2, range)
## var1 var2 var3
## [1,] 2.000432 4.401090 22005.30
## [2,] 3.499644 5.098867 23998.15
A completely-different approach is to create samples of
your features (this time of the same length), put them
into the columns of a matrix, and then rearrange the
elements within the columns so that you come close to
the desired correlation matrix. See this answer.