python - 如何从 Python 中的非正态多变量分布生成样本?
问题描述
我有一个包含 10 个变量和 100 行的输入数据框 df_input。这些数据不是正态分布的。我想生成一个包含 10 个变量和 10,000 行的输出数据帧,以便新数据帧的协方差矩阵和均值与原始数据帧的相同。输出变量不应呈正态分布,而应具有与输入变量相似的分布。即: Cov(df_output) = Cov(df_input) 和 mean(df_ouput) = mean(df_input) 有没有 Python 函数可以做到这一点?
注意: np.random.multivariate_normal(mean_input,Cov_input,10000) 几乎可以做到这一点,但输出变量是正态分布的,而我需要它们与输入具有相同(或相似)的分布。
解决方案
更新
我刚刚注意到你提到np.random.multivariate_normal
......它一下子就相当于gen_like()
下面!
我将把它留在这里以帮助人们理解其机制,但总结一下:
- 您可以将经验分布的均值和协方差与(旋转、缩放、平移)正态匹配;
- 为了更好地匹配更高的时刻,您应该查看 copula。
原始答案
由于您只对匹配两个第一时刻(均值、方差)感兴趣,因此可以使用简单的 PCA 来获得初始数据的合适模型。请注意,新生成的数据将是一个正常的椭圆体,经过旋转、缩放和平移以匹配初始数据的经验均值和协方差。
如果您想要对原始发行版进行更复杂的“复制”,那么您应该按照我在评论中所说的那样查看Copula 。
因此,仅在前两个时刻,假设您的输入数据是d0
:
from sklearn.decomposition import PCA
def gen_like(d0, n):
pca = PCA(n_components=d0.shape[1]).fit(d0)
z0 = pca.transform(d0) # z0 is centered and uncorrelated (cov is diagonal)
z1 = np.random.normal(size=(n, d0.shape[1])) * np.std(z0, 0)
# project back to input space
d1 = pca.inverse_transform(z1)
return d1
例子:
# generate some random data
# arbitrary transformation matrix
F = np.array([
[1, 2, 3],
[2, 1, 4],
[5, 1, 3],
])
d0 = np.random.normal(2, 4, size=(10000, 3)) @ F.T
np.mean(d0, 0)
# ex: array([12.12791066, 14.10333273, 17.95212292])
np.cov(d0.T)
# ex: array([[225.09691912, 257.39878551, 259.40288019],
# [257.39878551, 338.34087242, 373.4773562 ],
# [259.40288019, 373.4773562 , 566.29288861]])
# try to match mean, variance of d0
d1 = gen_like(d0, 10000)
np.allclose(np.mean(d0, 0), np.mean(d1, 0), rtol=0.1)
# often True (but not guaranteed)
np.allclose(np.cov(d0.T), np.cov(d1.T), rtol=0.1)
# often True (but not guaranteed)
有趣的是,您可以在圆孔中安装一个方形钉(即,证明实际上只有均值,方差匹配,而不是更高的时刻):
d0 = np.random.uniform(5, 10, size=(1000, 3)) @ F.T
d1 = gen_like(d0, 10000)
np.allclose(np.mean(d0, 0), np.mean(d1, 0), rtol=0.1)
# often True (but not guaranteed)
np.allclose(np.cov(d0.T), np.cov(d1.T), rtol=0.1)
# often True (but not guaranteed)
推荐阅读
- javascript - FullCalendar - 每天重复一个事件而不被告知
- javascript - 带有 iFrame 的网页
- mysql - 如何更新 MySQL 中不同值的每一行?
- android - 如何使用颤振中的键删除/清除共享首选项?
- python - Pandas 中的手动特征工程 - 1 列与所有其他列的平均值
- async-await - AXIOS 请求:“错误:连接 ECONNREFUSED 127.0.0.1:80”
- pandas - 如何将数据框日期转换为 csv 文件中的 yyyy-mm--dd 格式
- numpy - 绘制插值函数的等高线图:不同部分数据的不匹配结果
- java - Android:当我的应用程序在后台时,如何检测自拍杆按钮点击
- sql - SQL Query School Course pre 必修课