将数据拟合到分布?

时间:2010-11-27 04:10:11

标签: python r statistics scipy

我不是统计学家(更像是一位研究型网络开发人员),但我最近听到了很多关于scipyR的信息。因此,出于好奇,我想问这个问题(尽管对于这里的专家来说可能听起来很愚蠢),因为我不确定这方面的进展,并想知道没有合理统计背景的人如何处理这些问题。

考虑到从实验中观察到的一组实数,让我们说它们属于那里的许多分布之一(如Weibull,Erlang,Cauchy,Exponential等),是否有任何自动化方法可以找到正确的分布和数据的分布参数?是否有任何好的教程可以引导我完成整个过程?

真实场景: 例如,让我们说我发起了一项小型调查,并记录了一个人每天与300人谈话的人数,并且我有以下信息:

1 10
2 5
3 20
...
...

其中X Y告诉我X人在调查期间与Y人交谈过。现在使用来自300个人的信息,我想将其融入模型中。问题归结为是否有任何自动方法可以找到这些数据的正确分布和分布参数,如果没有,是否有一个很好的逐步程序来实现相同的目标?

6 个答案:

答案 0 :(得分:37)

这是一个复杂的问题,并没有完美的答案。我将尝试向您概述主要概念,并指出您对该主题的一些有用的阅读方向。

假设您是一维数据集,并且您拥有一组有限的概率分布函数,您认为这些函数可能是从中生成的。您可以单独考虑每个分布,并尝试根据您的数据查找合理的参数。 在给定数据的情况下,有两种方法可以设置概率分布函数的参数:

  1. Least Squares
  2. Maximum Likelihood
  3. 根据我的经验,近年来最大可能性是最佳选择,尽管在每个领域都可能并非如此。

    以下是如何估算R中参数的具体示例。考虑从高斯分布生成的一组随机点,均值为0且标准差为1:

    x = rnorm( n = 100, mean = 0, sd = 1 )
    

    假设您知道数据是使用高斯过程生成的,但您已经忘记(或永远不知道!)高斯参数。您希望使用这些数据来合理估算平均值和标准差。在R中,有一个标准库使这非常简单:

    library(MASS)
    params = fitdistr( x, "normal" )
    print( params )
    

    这给了我以下输出:

          mean           sd     
      -0.17922360    1.01636446 
     ( 0.10163645) ( 0.07186782)
    

    那些与正确答案非常接近,括号中的数字是参数周围的置信区间。请记住,每次生成一组新的点时,您都​​会得到估算值的新答案。

    在数学上,这是使用最大似然估计高斯的均值和标准差。可能性意味着(在这种情况下)“给定参数值的数据概率”。最大似然意味着“最大化生成输入数据概率的参数值”。最大似然估计是用于找到最大化生成输入数据的概率的参数值的算法,并且对于一些分布,它可以涉及numerical optimization算法。在R中,大部分工作由fitdistr完成,在某些情况下会调用optim

    您可以从参数中提取对数似然性,如下所示:

    print( params$loglik )
    [1] -139.5772
    

    使用对数似然而不是避免舍入错误的可能性更常见。估计数据的联合概率涉及概率乘以小于1.即使对于一小组数据,联合概率非常快地逼近0,并且添加数据的对数概率等于概率乘以。随着对数似然逼近0,可能性最大化,因此更多负数更适合您的数据。

    使用这样的计算工具,可以轻松估算任何分布的参数。考虑这个例子:

    x = x[ x >= 0 ]
    
    distributions = c("normal","exponential")
    
    for ( dist in distributions ) {
        print( paste( "fitting parameters for ", dist ) )
        params = fitdistr( x, dist )
        print( params )
        print( summary( params ) )
        print( params$loglik )
    }
    

    指数分布不会产生负数,所以我在第一行中删除了它们。输出(随机)看起来像这样:

    [1] "fitting parameters for  normal"
          mean          sd    
      0.72021836   0.54079027 
     (0.07647929) (0.05407903)
             Length Class  Mode   
    estimate 2      -none- numeric
    sd       2      -none- numeric
    n        1      -none- numeric
    loglik   1      -none- numeric
    [1] -40.21074
    [1] "fitting parameters for  exponential"
         rate  
      1.388468 
     (0.196359)
             Length Class  Mode   
    estimate 1      -none- numeric
    sd       1      -none- numeric
    n        1      -none- numeric
    loglik   1      -none- numeric
    [1] -33.58996
    

    指数分布实际上比正态分布更有可能生成此数据,可能是因为指数分布不必将任何概率密度分配给负数。

    当您尝试将数据与更多分布相匹配时,所有这些估算问题都会变得更糟。具有更多参数的分布更灵活,因此它们比具有更少参数的分布更适合您的数据。此外,某些发行版是其他发行版的特殊情况(例如,ExponentialGamma的特例)。因此,使用先验知识将您的选择模型约束到所有可能模型的子集是非常常见的。

    解决参数估计中的一些问题的一个技巧是生成大量数据,并为cross-validation留出一些数据。要交叉验证参数与数据的拟合,请将一些数据保留在估算过程之外,然后在剩余数据上测量每个模型的可能性。

答案 1 :(得分:10)

查看fitdistrplushttp://cran.r-project.org/web/packages/fitdistrplus/index.html)。

需要注意的几件事:

  • 尝试函数descdist,它提供了数据的偏斜与峰度的关系图,并显示了一些常见的分布。
  • fitdist允许您根据密度和cdf来拟合您可以定义的任何分布。
  • 然后,您可以使用gofstat来计算KS和AD统计数据,这些统计数据用于衡量数据距离的拟合距离。

答案 2 :(得分:5)

这可能比你需要的更为通用,但可能会给你一些东西。

从随机数据估计概率密度函数的一种方法是使用Edgeworth或Butterworth扩展。这些近似值使用称为cumulants的密度函数属性(无偏估计量为k-statistics),并将密度函数表示为高斯分布的扰动。

这两者都有一些相当可怕的弱点,例如产生发散密度函数,甚至是某些区域负面的密度函数。但是,有些人发现它们对于高度聚类的数据很有用,或者作为进一步估算的起点,或者用于分段估计的密度函数,或者作为启发式的一部分。

微米。 G. Kendall和A. Stuart,先进的统计理论,第一卷。 1, 查尔斯格里芬,1963年,是我发现的最完整的参考资料,有一整页专门讨论这个主题;大多数其他文本最多只有一个句子,或列出了时刻而不是累积量的扩展,这有点无用。祝你好好找一份副本,但是我不得不派我的大学图书管理员前往档案馆去旅行......但这是多年前的事,所以今天上网也许会更有帮助。

您问题的最常见形式是称为非参数密度估算的字段的主题,其中给出了:

  • 来自具有未知分布的随机流程的数据,
  • 对基础流程的约束

...您生成的密度函数最有可能产生数据。 (更现实地,您创建了一种在任何给定点计算此函数近似值的方法,您可以将其用于进一步的工作,例如,比较两组随机数据的密度函数,看它们是否可以来自同一个处理)。

就个人而言,我在使用非参数密度估算方面没什么好处,但是如果你有稳定的理智,你应该调查一下。

答案 3 :(得分:3)

您基本上想要将现实世界数据与一组理论分布进行比较。基数R中有函数qqnorm(),它将为正态分布执行此操作,但我更喜欢probplot中的e1071函数,它允许您测试其他分布。这是一个代码片段,它将根据我们粘贴到列表中的每个理论分布绘制您的实际数据。我们使用plyr来浏览列表,但还有其他几种方法可以浏览列表。

library("plyr") 
library("e1071")

realData <- rnorm(1000) #Real data is normally distributed

distToTest <- list(qnorm = "qnorm", lognormal = "qlnorm", qexp =  "qexp")

#function to test real data against list of distributions above. Output is a jpeg for each distribution.
testDist <- function(x, data){
    jpeg(paste(x, ".jpeg", sep = ""))
    probplot(data, qdist = x)
    dev.off()
    }

l_ply(distToTest, function(x) testDist(x, realData))

答案 4 :(得分:2)

我不是科学家,但如果你用铅笔和纸做,那么显而易见的方法是制作图表,然后将图表与已知的标准分布进行比较。

进一步考虑这个想法,“比较”是看标准分布和你的曲线是否相似。

三角学,切线......这是我最后的想法。

我不是专家,只是另一个卑微的Web开发人员=)

答案 5 :(得分:-4)

对于它的价值,似乎你可能想看看泊松分布。