【问题标题】:generating correlated numbers in numpy / pandas在 numpy / pandas 中生成相关数字
【发布时间】:2018-02-07 17:22:52
【问题描述】:

我正在尝试生成 4 个科目的模拟学生成绩,其中学生记录是单行数据。此处显示的代码将生成均值为 60、标准差为 15 的正态分布随机数。

df = pd.DataFrame(15 * np.random.randn(5, 4) + 60, columns=['Math', 'Science', 'History', 'Art'])

我想不通的是如何让学生的科学成绩与数学成绩高度相关,而他们的历史和艺术成绩则不太相关,但仍与数学成绩有一定的相关性。

我既不是统计学家也不是专家级程序员,所以我希望有一个不太复杂但更容易理解的解决方案。

【问题讨论】:

  • 您有任何成绩数据可以证明这些相关性吗?这将使生成有效的协方差矩阵更容易。您无需在此处发布(隐私),只需将数据采用何种格式即可。
  • 无论如何,您想要的是生成平均向量和协方差矩阵,并使用scipy.stats.multivariate_normal.rvs() 生成具有该分布的随机数据。

标签: python pandas numpy statistics correlation


【解决方案1】:

让我们将@Daniel 的建议放入代码中。

第 1 步

让我们导入multivariate_normal

import numpy as np
from scipy.stats import multivariate_normal as mvn

第 2 步

让我们构造协方差数据并生成数据:

cov = np.array([[1, 0.8,.7, .6],[.8,1.,.5,.5],[0.7,.5,1.,.5],[0.6,.5,.5,1]])
cov

array([[ 1. ,  0.8,  0.7,  0.6],
       [ 0.8,  1. ,  0.5,  0.5],
       [ 0.7,  0.5,  1. ,  0.5],
       [ 0.6,  0.5,  0.5,  1. ]])

这是关键步骤。请注意,协方差矩阵在对角线上有1's,并且随着您从左向右移动,协方差会减小。

现在我们准备生成数据,让我们坐下 1'000 个点:

scores = mvn.rvs(mean = [60.,60.,60.,60.], cov=cov, size = 1000)

完整性检查(从协方差矩阵到简单的相关性):

np.corrcoef(scores.T):

array([[ 1.        ,  0.78886583,  0.70198586,  0.56810058],
       [ 0.78886583,  1.        ,  0.49187904,  0.45994833],
       [ 0.70198586,  0.49187904,  1.        ,  0.4755558 ],
       [ 0.56810058,  0.45994833,  0.4755558 ,  1.        ]])

请注意,np.corrcoef 期望您的数据成行。

最后,让我们将你的数据放入 Pandas 的DataFrame

df = pd.DataFrame(data = scores, columns = ["Math", "Science","History", "Art"])
df.head()

    Math        Science     History     Art
0   60.629673   61.238697   61.805788   61.848049
1   59.728172   60.095608   61.139197   61.610891
2   61.205913   60.812307   60.822623   59.497453
3   60.581532   62.163044   59.277956   60.992206
4   61.408262   59.894078   61.154003   61.730079

第 3 步

让我们可视化我们刚刚生成的一些数据:

ax = df.plot(x = "Math",y="Art", kind="scatter", color = "r", alpha = .5, label = "Art, $corr_{Math}$ = .6")
df.plot(x = "Math",y="Science", kind="scatter", ax = ax, color = "b", alpha = .2, label = "Science, $corr_{Math}$ = .8")
ax.set_ylabel("Art and Science");

【讨论】:

    【解决方案2】:

    谢谢大家的回复;它们非常有用。我修改了 Sergey 提供的代码以生成我正在寻找的结果,即数学和科学标记在大多数时间相对接近的记录,而历史和艺术标记则更加独立。

    以下生成的数据看起来合理:

    cov = np.array([[1, 0.5,.2, .1],[.5,1.,.1,.1],[0.2,.1,1,.3],[0.1,.1,.3,1]])
    scores = mvn.rvs(mean = [0.,0.,0.,0.], cov=cov, size = 100)
    df = pd.DataFrame(data = 15 * scores + 60, columns = ["Math","Science","History", "Art"])
    df.head(10)
    

    下一步是让每个主题都有不同的意思,但我知道如何做到这一点。再次感谢。

    example dataframe

    【讨论】:

      【解决方案3】:

      对此的统计工具是协方差矩阵:https://en.wikipedia.org/wiki/Covariance。 每个单元格 (i,j) 代表变量 i 和变量 j 之间的依赖关系,因此在您的情况下,它可以介于数学和科学之间。如果没有依赖关系,则值为 0。

      您所做的是假设协方差是对角线上具有相同值的对角矩阵。所以你要做的是定义你的协方差矩阵,然后用numpy.random.multivariate_normalhttps://docs.scipy.org/doc/numpy/reference/generated/numpy.random.multivariate_normal.html或任何其他分布函数从高斯中抽取样本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-04
        • 2010-12-15
        • 2018-10-10
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 2022-01-04
        • 2013-04-08
        相关资源
        最近更新 更多