<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>统计之都 &#187; 统计计算</title>
	<atom:link href="http://cos.name/category/compstat/feed/" rel="self" type="application/rss+xml" />
	<link>http://cos.name</link>
	<description>中国统计学门户网站，免费统计学服务平台</description>
	<lastBuildDate>Mon, 06 Sep 2010 01:21:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>从中心极限定理的模拟到正态分布</title>
		<link>http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/</link>
		<comments>http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comments</comments>
		<pubDate>Sun, 09 May 2010 04:24:58 +0000</pubDate>
		<dc:creator>谢益辉</dc:creator>
				<category><![CDATA[概率论与数理统计]]></category>
		<category><![CDATA[统计图形]]></category>
		<category><![CDATA[统计计算]]></category>
		<category><![CDATA[R语言]]></category>
		<category><![CDATA[SAS]]></category>
		<category><![CDATA[Shapiro检验]]></category>
		<category><![CDATA[中心极限定理]]></category>
		<category><![CDATA[动画]]></category>
		<category><![CDATA[密度曲线]]></category>
		<category><![CDATA[数学假设条件]]></category>
		<category><![CDATA[样本均值]]></category>
		<category><![CDATA[样本量]]></category>
		<category><![CDATA[正态分布]]></category>
		<category><![CDATA[泰勒展开]]></category>
		<category><![CDATA[直方图]]></category>
		<category><![CDATA[统计模拟]]></category>
		<category><![CDATA[钟形曲线]]></category>
		<category><![CDATA[随机变量]]></category>

		<guid isPermaLink="false">http://cos.name/?p=2186</guid>
		<description><![CDATA[昨日翻看朱世武老师的《金融计算与建模》幻灯片（来源，幻灯片“13随机模拟基础”），其中提到了中心极限定理（Central Limit Theorem，下文简称CLT）及其SAS模拟实现。由于我一直觉得我们看到的大多数对CLT的模拟都有共同的误导性，因此在此撰文讲述我的观点，希望能说清楚CLT的真实面目，让读者对它有更深刻的理解。 一、中心极限定理说了什么 从广义的角度来讲，CLT说的是一些随机变量之和（在n趋于无穷的时候）趋于正态分布，条件是这些随机变量之间相关性不要太严重，每个随机变量自身的方差相对来说不要太大。我们平时看到的都是CLT的最简单的形式：随机变量独立同分布，方差有限。实际上独立同分布不是必要的条件。要理解这段话，我们就得去思考一下Lindeberg条件或Liapounov条件的含义，以及非独立情况下的CLT。而CLT为什么偏偏选中了正态分布呢？这主要是泰勒展开的功劳（注1），加上特征函数作为“催化剂”，捣鼓半天，最后一看，特征函数的极限形式正是正态分布。本文不打算走到这样偏僻的数学角落，只是先介绍一下CLT的前世今生，当我们在统计理论上犯迷糊的时候，回溯到事情的最原始状态，往往能让头脑更清醒（注2）。 即使是最简单的CLT，我觉得几乎所有做模拟的人都走入了一个误区，就是把钟形密度曲线解释为正态分布。给一个非正态的总体分布，重复计算若干次样本均值，把密度以直方图或密度曲线的形式画出来，给观众们说，看：钟形曲线！群众们一看，哇，原本是左偏/右偏/水平的密度，现在真的变成了对称的钟形曲线。于是乎不得不信服CLT的魔力。 二、中心极限定理的模拟 我们缺的不是钟形曲线，而是样本均值的分布和正态分布差多少的指标。这一点在下面第3小节中再谈，先看几个常见的模拟例子。 1、对称的钟形曲线不代表正态分布 很多人喜欢用掷骰子的例子来讲中心极限定理，大意是将两次独立掷骰子的结果加起来，看这个和的分布。我犹记当年人大一位老师给我们上抽样就举了这个例子说明CLT的魔力：看，即使样本量为2，得到的分布也是正态分布！恰好昨天在朱老师的幻灯片中又看到这个例子，不禁感叹这样一个糟糕的例子竟然经久不衰。这个例子的骗局在哪儿呢？其实很简单：在于掷骰子得到的结果的“对称性”，换句话说，结果是1、2、3、4、5、6，这6个数字围绕其均值3.5左右对称，因此两次骰子的结果加起来也围绕7对称，再画个图，两边低，中间高，看似正态分布好像出来了。朱老师的SAS代码如下： data a; do x1=1 to 6; do x2=1 to 6; output; end; end; /*模拟掷骰子两次，生成36行数据*/ data a; set a; x=sum(x1,x2); proc univariate data=a noprint; var x; histogram/normal (mu=est sigma=est); run; 先跑题说一处细节：这段代码中的直方图不合适，因为我们知道结果x只可能是整数，而（SAS）直方图默认的分组也会以整数为边界，每个边界上的整数都被归到右边的条中去了，而这个所谓的直方图其实只是个条形图：展示每种结果的频数。所以这种情况下认为指定非整数的分组边界才能显示数据真实的分布。以下是R代码： x = rowSums(expand.grid(1:6, 1:6)) hist(x, breaks = seq(min(x) - 0.5, max(x) + 0.5, 1), main [...]]]></description>
			<content:encoded><![CDATA[<p>昨日翻看朱世武老师的《金融计算与建模》幻灯片（<a href="http://cos.name/cn/topic/15637" target="_blank" rel='nofollow'>来源</a>，幻灯片“13随机模拟基础”），其中提到了中心极限定理（Central Limit Theorem，下文简称CLT）及其SAS模拟实现。由于我一直觉得我们看到的大多数对CLT的模拟都有共同的误导性，因此在此撰文讲述我的观点，希望能说清楚CLT的真实面目，让读者对它有更深刻的理解。</p>
<h2>一、中心极限定理说了什么</h2>
<p>从广义的角度来讲，CLT说的是一些随机变量之和（在n趋于无穷的时候）趋于正态分布，条件是这些随机变量之间相关性不要太严重，每个随机变量自身的方差相对来说不要太大。我们平时看到的都是CLT的最简单的形式：随机变量独立同分布，方差有限。实际上独立同分布不是必要的条件。要理解这段话，我们就得去思考一下Lindeberg条件或Liapounov条件的含义，以及非独立情况下的CLT。而CLT为什么偏偏选中了正态分布呢？这主要是泰勒展开的功劳（注1），加上特征函数作为“催化剂”，捣鼓半天，最后一看，特征函数的极限形式正是正态分布。本文不打算走到这样偏僻的数学角落，只是先介绍一下CLT的前世今生，当我们在统计理论上犯迷糊的时候，回溯到事情的最原始状态，往往能让头脑更清醒（注2）。</p>
<p>即使是最简单的CLT，我觉得几乎所有做模拟的人都走入了一个误区，就是把钟形密度曲线解释为正态分布。给一个非正态的总体分布，重复计算若干次样本均值，把密度以直方图或密度曲线的形式画出来，给观众们说，看：钟形曲线！群众们一看，哇，原本是左偏/右偏/水平的密度，现在真的变成了对称的钟形曲线。于是乎不得不信服CLT的魔力。</p>
<h2>二、中心极限定理的模拟</h2>
<p>我们缺的不是钟形曲线，而是样本均值的分布和正态分布差多少的指标。这一点在下面第3小节中再谈，先看几个常见的模拟例子。</p>
<h3>1、对称的钟形曲线不代表正态分布</h3>
<p>很多人喜欢用掷骰子的例子来讲中心极限定理，大意是将两次独立掷骰子的结果加起来，看这个和的分布。我犹记当年人大一位老师给我们上抽样就举了这个例子说明CLT的魔力：看，即使样本量为2，得到的分布也是正态分布！恰好昨天在朱老师的幻灯片中又看到这个例子，不禁感叹这样一个糟糕的例子竟然经久不衰。这个例子的骗局在哪儿呢？其实很简单：在于掷骰子得到的结果的“对称性”，换句话说，结果是1、2、3、4、5、6，这6个数字围绕其均值3.5左右对称，因此两次骰子的结果加起来也围绕7对称，再画个图，两边低，中间高，看似正态分布好像出来了。朱老师的SAS代码如下：</p>
<pre>data a;
do x1=1 to 6;
do x2=1 to 6;
output;
end;
end;  /*模拟掷骰子两次，生成36行数据*/
data a;
set a;
x=sum(x1,x2);
proc univariate data=a noprint;
var x;
histogram/normal (mu=est sigma=est);
run;</pre>
<p>先跑题说一处细节：这段代码中的直方图不合适，因为我们知道结果x只可能是整数，而（SAS）直方图默认的分组也会以整数为边界，每个边界上的整数都被归到右边的条中去了，而这个所谓的直方图其实只是个条形图：展示每种结果的频数。所以这种情况下认为指定非整数的分组边界才能显示数据真实的分布。以下是R代码：</p>
<pre>x = rowSums(expand.grid(1:6, 1:6))
hist(x, breaks = seq(min(x) - 0.5, max(x) + 0.5, 1), main = "")
</pre>
<div id="attachment_2187" class="wp-caption aligncenter" style="width: 310px"><img class="size-full wp-image-2187" title="两次掷骰子得到的结果之和的分布" src="http://cos.name/wp-content/uploads/2010/05/sim-dice-hist.png" alt="两次掷骰子得到的结果之和的分布" width="300" height="300" /><p class="wp-caption-text">两次掷骰子得到的结果之和的分布</p></div>
<p>样本量为2的时候真的得到正态分布了么？CLT确实有它的神奇之处，但还没那么神奇。以上结果如我前文所说，仅仅是由于样本空间中的元素的对称性，所以得到了一副对称的图形，看起来像是正态分布，如果我们再用另外6个数字试验一下，马上就看穿这种迷惑了，我把最后一个数字换成15再看直方图：</p>
<pre>d = c(1, 2, 3, 4, 5, 15)
x = rowSums(expand.grid(d, d))
hist(x, breaks = seq(min(x) - 0.5, max(x) + 0.5, 1), main = "")
</pre>
<div id="attachment_2188" class="wp-caption aligncenter" style="width: 310px"><img class="size-full wp-image-2188" title="6个数字中2个样本之和的分布" src="http://cos.name/wp-content/uploads/2010/05/sim-6num-hist.png" alt="6个数字中2个样本之和的分布" width="300" height="300" /><p class="wp-caption-text">6个数字中2个样本之和的分布</p></div>
<p>如何？“正态分布”哪里去了？客官是否能看清骰子中的中心极限定理谎言了？</p>
<h3>2、直方图上添加正态密度曲线有误导性</h3>
<p>在我还会用SPSS的年代（大约是SPSS 15.0），我就发现SPSS的一个荒唐之处，它的直方图有个选项，可以控制是否添加正态密度曲线。我们被“正态”毒害得多深，从这些软件设置就可以看出来。为什么只能加正态密度曲线，而不能加数据自身反映出来的核密度估计曲线？换句话说，数据的分布一定要是正态么？</p>
<p>我们看CLT的模拟，很多人也喜欢在直方图上加上正态分布密度曲线，这有一定道理：可以看直方图跟正态密度的差异有多大。然而，我们却很少见直方图上的核密度曲线（注3）。既然是要作比较，就拿最可比的去比，比如曲线对曲线，直方图对直方图，人眼本来就是不精确的测量工具，那么制图者就应该提供尽量准确而方便的参照系。</p>
<h3>3、给出拟合好坏的指标</h3>
<p>综上，我在两年多以前已经把这些CLT模拟的想法写成函数收录在R包<a title="http://cran.r-project.org/web/packages/animation/index.html" href="http://cran.r-project.org/web/packages/animation/index.html" target="_blank" rel='nofollow'>animation</a>中，参见函数<code>clt.ani()</code>。代码及输出如下：</p>
<pre>if (!require(animation)) install.packages("animation")
library(animation)
ani.options(interval = 0.1, nmax = 100)
par(mar = c(4, 4, 1, 0.5))
clt.ani()</pre>
<div id="attachment_2189" class="wp-caption aligncenter" style="width: 490px"><img class="size-full wp-image-2189" title="中心极限定理模拟：从指数分布到正态分布" src="http://cos.name/wp-content/uploads/2010/05/clt-rexp-demo.gif" alt="中心极限定理模拟：从指数分布到正态分布" width="480" height="480" /><p class="wp-caption-text">中心极限定理模拟：从指数分布到正态分布</p></div>
<p>这个CLT模拟的过程很简单：给一个总体分布（默认为右偏的指数分布），在给定样本量n时不断重复抽样分别计算样本均值，一直这样计算obs个均值，并画出它们的直方图和相应的核密度估计曲线；然后随着n增大，看相应的样本均值分布如何。此外，我使用了Shapiro正态性检验来检验这些均值的正态性，并把P值取出来画在下半幅图中。这样我们就很清楚地知道，对于每一种样本量（n = 1, &#8230;, 100），我们的样本均值究竟离正态分布多远。此处P值就充当了一个拟合好坏的指标。可以看出，上面的动画中，当样本量n超过20之后，P值会普遍偏大，也就是样本均值的分布和正态分布比较接近（严格来说，是“不能拒绝正态分布”），但也不能保证样本量大就一定意味着正态分布，譬如上图中n=40的时候P值就很小。</p>
<h2>三、小结</h2>
<p>正态分布在统计中的地位如此之重要，以至于人们几乎认为正态是一种自然而然的分布，本文想说明的是，正态有它的自然性（参见注1），但我们不能逮着两边低中间高的东西都叫正态（参见小学课文<a title="http://yihui.name/cn/2009/01/bell-shaped-curve-and-density-estimation/" href="http://yihui.name/cn/2009/01/bell-shaped-curve-and-density-estimation/" target="_blank" rel='nofollow'>《小蝌蚪找妈妈》</a>）；做模型或分析数据之前，先清空脑子里的这种“<a title="http://yihui.name/cn/2009/02/gaussian-distribution-and-statistical-dogmatism/" href="http://yihui.name/cn/2009/02/gaussian-distribution-and-statistical-dogmatism/" target="_blank" rel='nofollow'>正态教义</a>”，用事实说话。</p>
<p>另外，前面胡江堂挖了个大坑，大家跳进去争论了半天SAS和R的问题，我在这里也挖个小坑：就模拟而言，如果有SAS用户愿意研究一下，我想知道朱老师的SAS模拟代码是否有改进的余地。SAS自70年代创立，过了二十多年才引进“函数”这种杀人越货编程必备之工具，一直以来都是“宏”的天下，说它“恐龙”应该也不冤枉吧。朱老师幻灯片中的长篇SAS代码，如果用R改写，应该都不会超过三五行甚至一行（注4），而反过来可能就麻烦了，比如上面的动画（用SAS怎么写？），它用R之所以方便，是因为R大量的统计相关的函数可任意调用，而图形也很灵活，可以把P值动态写在图例的位置，也可以愿意把样本量n作为下标动态写在<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cbar%7BX%7D" title="\bar{X}" alt="\bar{X}" align="absmiddle" />旁边。</p>
<h2>脚注</h2>
<p><strong>注1</strong>：以我的浅见，统计学中绝大多数极限正态分布的来源都是泰勒展开，主要是因为泰勒展开中有一个平方项，这个东西和正态分布的密度函数（或特征函数）看起来形式相似，再加上一些对高次项的假设（使它们在极限中消去），正态分布也就来了。另一个典型例子是极大似然估计的渐近正态性：泰勒展开中一阶导数为零，剩下二阶像正态。此外，正态分布有个独特的特点，就是它的密度函数和特征函数长得很像，冥冥之中也主导了很多统计量的分布（这一点我还没太想清楚）。</p>
<p><strong>注2</strong>：我很少见统计学家强调这种想法的重要性，仿佛大家都埋在公式堆里都推导得倍儿高兴。有两个例外：一个是Brian Ripley教授，我在看他的一份幻灯片<a href="http://www.stats.ox.ac.uk/%7Eripley/Nelder80.pdf" rel='nofollow'>Selecting  amongst large classes of models</a>的时候发现他竟然回顾了AIC的假设条件——这是我见过的唯一一个讲模型选择时会回到数学根源的人；另一个是Ripley的老搭档，Bill Venables，他在他那著名的手稿<a href="http://www.stats.ox.ac.uk/pub/MASS3/Exegeses.pdf" rel='nofollow'>Exegeses  on Linear Models</a>中竟然从泰勒展开来说线性模型的来历，这也是我在所有我读过的线性模型相关的文章和书中看到的唯一一份从泰勒展开角度谈线性模型的材料。我个人并不喜欢数学，但我喜欢看思路。</p>
<p><strong>注3</strong>：我的观点是，画直方图尽量加上核密度估计曲线，因为它能刻画数据在任意位置上的密度大小，而直方图的形状则完全受制于分组边界的位置。当然，核密度估计曲线也取决于核函数，但大多数情况下，核函数不会对曲线的形状有太大的影响。不过邱怡轩在前面“<a title="Permanent Link to 有边界区间上的核密度估计" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/" rel='nofollow'>有边界区间上的核密度估计</a>”一文中提到的问题很值得注意。</p>
<p><strong>注4</strong>：伯努利随机变量之和的分布。SAS代码：</p>
<pre>symbol;
goptions ftext= ctext= htext=;

%macro a(n);
data rv;
retain _seed_ 0;
do _i_ = 1 to &amp;n;
binom1 = ranbin(_seed_,&amp;n,0.8); /*ranbin函数返回以seed、n、0.8为参数的二项分布随机变量*/
output;
end;
drop _seed_ _i_;
run;
%mend;

%a(100);

proc univariate data=rv noprint;
var binom1;
histogram/normal( mu=est sigma=est);
inset normal ;
run;</pre>
<p>R代码：</p>
<pre>a = function(n) hist(rbinom(n, n, 0.8))</pre>
<p>什么叫向量化编程？这就是R它爹S语言诞生的原因之一：统计学的编程不应该涉及到那么多繁琐的循环。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/01/r-and-sas-new-york-times/" title="R与SAS之争：一个导读">R与SAS之争：一个导读</a> (28)</li><li><a href="http://cos.name/2008/12/decision-and-risk/" title="决策与风险">决策与风险</a> (8)</li><li><a href="http://cos.name/2008/12/my-experience-with-statistics-by-chongjie-liu/" title="刘重杰：和统计接触的经历">刘重杰：和统计接触的经历</a> (4)</li><li><a href="http://cos.name/2008/11/which-statistical-software-should-we-use/" title="统计学专业应该使用什么样的统计软件（写给在统计学院学习的学弟学妹之四）">统计学专业应该使用什么样的统计软件（写给在统计学院学习的学弟学妹之四）</a> (37)</li><li><a href="http://cos.name/2008/11/probability-theory-origin-development-application/" title="概率论的起源、发展、应用">概率论的起源、发展、应用</a> (5)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >范建宁</a> : <a class="comment_content" href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comment-1543" title="View the entire comment by 范建宁" >中心极限定理没有错，但是样本量为2的时候话中心极限定理，这是没有真正理解“极限”的含义。</a></li>
<li><a class="commentor" href="http://yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comment-1504" title="View the entire comment by 谢益辉" >谢谢，这个建议很好，固定坐标轴范围之后可以明显观察到：样本均值的分布越来越集中于一个点，即：x轴越来...</a></li>
<li><a class="commentor" href="http://www.etsir.com" >徐梁君</a> : <a class="comment_content" href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comment-1503" title="View the entire comment by 徐梁君" >中间的gif演示建议把纵轴min-max固定</a></li>
<li><a class="commentor" href="http://yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comment-1478" title="View the entire comment by 谢益辉" >所以说向量化编程可以减轻统计工作者的编程任务啊，R把这些常见的功能都封装到底层语言中，代码写起来既轻...</a></li>
<li><a class="commentor" href="http://jiangtanghu.com/" >胡江堂</a> : <a class="comment_content" href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/#comment-1476" title="View the entire comment by 胡江堂" >to xin,

你是对的，ranbin()产生一个随机数，n个循环则产生n个随机数。我提到SA...</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>有边界区间上的核密度估计</title>
		<link>http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/</link>
		<comments>http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comments</comments>
		<pubDate>Sun, 11 Apr 2010 05:07:51 +0000</pubDate>
		<dc:creator>邱怡轩</dc:creator>
				<category><![CDATA[推荐文章]]></category>
		<category><![CDATA[统计图形]]></category>
		<category><![CDATA[统计理论]]></category>
		<category><![CDATA[统计计算]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[非参数统计]]></category>
		<category><![CDATA[偏差]]></category>
		<category><![CDATA[核密度估计]]></category>
		<category><![CDATA[模拟]]></category>
		<category><![CDATA[边界]]></category>

		<guid isPermaLink="false">http://cos.name/?p=2060</guid>
		<description><![CDATA[一、一个例子 核密度估计应该是大家常用的一种非参数密度估计方法，从某种程度上来说它的性质比直方图更好，可以替代直方图来展示数据的密度分布。但是相信大家会经常遇到一个问题，那就是有些数据是严格大于或等于零的，在这种情况下，零附近的密度估计往往会出现不理想的情况。下面以一个指数分布的模拟数据为例（样本量为1000），R程序代码为： set.seed(123); x=rexp(1000,1); plot(density(x,kernel="epanechnikov"),ylim=c(0,1.2)); lines(seq(0,8,by=0.02),dexp(seq(0,8,by=0.02),1),col="blue"); abline(v=0,col="red"); 可以看出，理论上应该单调递减的密度函数在0附近有明显的“陡坡”，而且不应该有密度的小于零的区域也有着正的估计值。当样本量增大时，这种现象也不会得到明显好转，下图是将样本量改为10000时的情形。 set.seed(123); x=rexp(10000,1); plot(density(x,kernel="epanechnikov"),ylim=c(0,1.2)); lines(seq(0,8,by=0.02),dexp(seq(0,8,by=0.02),1),col="blue"); abline(v=0,col="red"); 我们也许从平时看的书中了解到，当样本量趋于无穷时，核密度估计值将是收敛到真实的密度函数的，但我们可能不会特意去研究那些结论成立的条件。以上这两个简单的例子似乎给了我们一个直观的感觉，那就是当真实密度函数的支集（函数f(x)的支集指的是使得f(x)≠0的x的集合）有边界时，核密度估计值可能会出现一些不理想的情况。下面就简单地给出一些理论的结果。 二、理论分析 在一些必要的条件下（真实的密度函数f二阶导绝对连续，三阶导平方可积），核密度估计值的偏差有表达式，其中h是带宽，，k(u)是支集为[-1,1]的核函数（即在[-1,1]上有值，其余的地方取零）。可以看出这个偏差是随着带宽h的减小以的速度趋于零的。 而假设密度函数以0为边界，那么上述表达式将不再成立，而是代之以 其中。可以看出，当x&#62;=h时，，，此时的偏差跟之前的那个表达式没有区别；但当0&#60;=x&#60;h时，和都是非零的，于是偏差总是存在。 也许你会提议说，将估计值除以，偏差就可以减小了吧？的确，这样是一种改进的办法，但也要注意到，此时h的一次项不会消除，也就是说原来的衰减速度放慢到了h，从效率上说相对于理想的情况是大打了折扣。 这时候一个巧妙的办法是，用另外一个核函数l(x)对f也做一次估计，那么就有 其中的和意义类似，只不过是针对l(x)的。 对以上两个式子进行线性组合，则会有 然后把f(x)的系数移到等式左边，O(h)项的偏差就神奇地消失了。 通过观察核密度估计的表达式，我们可以将上面这个过程等价地认为是对f(x)用了一个新的核函数进行估计，这个新的核函数是 特别地，如果将l(x)取为x*k(x)，那么p(x)将有一个简单的形式 当x&#62;=h时，这个新的核函数p(x)就是k(x)，而当0&#60;=x&#60;h时（也就是在边界），它会对最初的核函数进行调整。当x&#60;0时，不管算出来的估计值是多少，都只需将密度的估计值取为0即可。 三、程序实现 下面这段程序是对本文的第一幅图进行“整容”，代码及效果图如下： k=function(x) 3/4*(1-x^2)*(abs(x)&#60;=1); a0=function(u,h) { lb=-1; ub=pmin(u/h,1); 0.75*(ub-lb)-0.25*(ub^3-lb^3); } a1=function(u,h) { lb=-1; ub=pmin(u/h,1); 3/8*(ub^2-lb^2)-3/16*(ub^4-lb^4); } a2=function(u,h) { lb=-1; ub=pmin(u/h,1); 0.25*(ub^3-lb^3)-0.15*(ub^5-lb^5); } kernel.new=function(x,u,h) { k(x)*(a2(u,h)-a1(u,h)*x)/(a0(u,h)*a2(u,h)-a1(u,h)^2); } den.est=function(u,ui,h) { sapply(u,function(u) [...]]]></description>
			<content:encoded><![CDATA[<h2>一、一个例子</h2>
<p>核密度估计应该是大家常用的一种非参数密度估计方法，从某种程度上来说它的性质比直方图更好，可以替代直方图来展示数据的密度分布。但是相信大家会经常遇到一个问题，那就是有些数据是严格大于或等于零的，在这种情况下，零附近的密度估计往往会出现不理想的情况。下面以一个指数分布的模拟数据为例（样本量为1000），R程序代码为：</p>
<pre>set.seed(123);
x=rexp(1000,1);
plot(density(x,kernel="epanechnikov"),ylim=c(0,1.2));
lines(seq(0,8,by=0.02),dexp(seq(0,8,by=0.02),1),col="blue");
abline(v=0,col="red");</pre>
<p><a href="http://cos.name/wp-content/uploads/2010/04/kde_original_kernel_n1000.png" rel='nofollow'><img class="aligncenter size-full wp-image-2061" title="原始核函数（样本量1000）" src="http://cos.name/wp-content/uploads/2010/04/kde_original_kernel_n1000.png" alt="" width="500" height="500" / rel='nofollow'></a></p>
<p>可以看出，理论上应该单调递减的密度函数在0附近有明显的“陡坡”，而且不应该有密度的小于零的区域也有着正的估计值。当样本量增大时，这种现象也不会得到明显好转，下图是将样本量改为10000时的情形。</p>
<pre>set.seed(123);
x=rexp(10000,1);
plot(density(x,kernel="epanechnikov"),ylim=c(0,1.2));
lines(seq(0,8,by=0.02),dexp(seq(0,8,by=0.02),1),col="blue");
abline(v=0,col="red");</pre>
<p><a href="http://cos.name/wp-content/uploads/2010/04/kde_original_kernel_n10000.png" rel='nofollow'><img class="aligncenter size-full wp-image-2062" title="原始核函数（样本量10000）" src="http://cos.name/wp-content/uploads/2010/04/kde_original_kernel_n10000.png" alt="" width="500" height="500" / rel='nofollow'></a></p>
<p>我们也许从平时看的书中了解到，当样本量趋于无穷时，核密度估计值将是收敛到真实的密度函数的，但我们可能不会特意去研究那些结论成立的条件。以上这两个简单的例子似乎给了我们一个直观的感觉，那就是当真实密度函数的支集（函数f(x)的支集指的是使得f(x)≠0的x的集合）有边界时，核密度估计值可能会出现一些不理想的情况。下面就简单地给出一些理论的结果。</p>
<h2>二、理论分析</h2>
<p>在一些必要的条件下（真实的密度函数f二阶导绝对连续，三阶导平方可积），核密度估计值<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Chat%7Bf%7D%28x%29" title="\hat{f}(x)" alt="\hat{f}(x)" align="absmiddle" />的偏差有表达式<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize Bias%5B%5Chat%7Bf%7D%28x%29%5D%3D%5Cfrac%7Bh%5E2%5Csigma_k%5E2f%27%27%28x%29%7D%7B2%7D%2BO%28h%5E4%29" title="Bias[\hat{f}(x)]=\frac{h^2\sigma_k^2f&#039;&#039;(x)}{2}+O(h^4)" alt="Bias[\hat{f}(x)]=\frac{h^2\sigma_k^2f&#039;&#039;(x)}{2}+O(h^4)" align="absmiddle" />，其中h是带宽，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Csigma_k%5E2%3D%5Cint%20u%5E2k%28u%29du" title="\sigma_k^2=\int u^2k(u)du" alt="\sigma_k^2=\int u^2k(u)du" align="absmiddle" />，k(u)是支集为[-1,1]的核函数（即在[-1,1]上有值，其余的地方取零）。可以看出这个偏差是随着带宽h的减小以<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize h%5E2" title="h^2" alt="h^2" align="absmiddle" />的速度趋于零的。</p>
<p>而假设密度函数以0为边界，那么上述表达式将不再成立，而是代之以<br />
<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize E%5B%5Chat%7Bf%7D_k%28x%29%5D%3Da_0%28x%29f%28x%29-ha_1%28x%29f%27%28x%29%2BO%28h%5E2%29" title="E[\hat{f}_k(x)]=a_0(x)f(x)-ha_1(x)f&#039;(x)+O(h^2)" alt="E[\hat{f}_k(x)]=a_0(x)f(x)-ha_1(x)f&#039;(x)+O(h^2)" align="absmiddle" /><br />
其中<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_i%28x%29%3D%5Cint_%7B-1%7D%5E%7Bx%2Fh%7Du%5Eik%28u%29du" title="a_i(x)=\int_{-1}^{x/h}u^ik(u)du" alt="a_i(x)=\int_{-1}^{x/h}u^ik(u)du" align="absmiddle" />。可以看出，当x&gt;=h时，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_0%28x%29%3D1" title="a_0(x)=1" alt="a_0(x)=1" align="absmiddle" />，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_1%28x%29%3D0" title="a_1(x)=0" alt="a_1(x)=0" align="absmiddle" />，此时的偏差跟之前的那个表达式没有区别；但当0&lt;=x&lt;h时，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_0%28x%29" title="a_0(x)" alt="a_0(x)" align="absmiddle" />和<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_1%28x%29" title="a_1(x)" alt="a_1(x)" align="absmiddle" />都是非零的，于是偏差总是存在。</p>
<p>也许你会提议说，将估计值除以<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_0%28x%29" title="a_0(x)" alt="a_0(x)" align="absmiddle" />，偏差就可以减小了吧？的确，这样是一种改进的办法，但也要注意到，此时h的一次项不会消除，也就是说原来<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize h%5E2" title="h^2" alt="h^2" align="absmiddle" />的衰减速度放慢到了h，从效率上说相对于理想的情况是大打了折扣。</p>
<p>这时候一个巧妙的办法是，用另外一个核函数l(x)对f也做一次估计，那么就有<br />
<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize E%5B%5Chat%7Bf%7D_l%28x%29%5D%3Db_0%28x%29f%28x%29-hb_1%28x%29f%27%28x%29%2BO%28h%5E2%29" title="E[\hat{f}_l(x)]=b_0(x)f(x)-hb_1(x)f&#039;(x)+O(h^2)" alt="E[\hat{f}_l(x)]=b_0(x)f(x)-hb_1(x)f&#039;(x)+O(h^2)" align="absmiddle" /><br />
其中的<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize b_0" title="b_0" alt="b_0" align="absmiddle" />和<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize b_1" title="b_1" alt="b_1" align="absmiddle" />意义类似，只不过是针对l(x)的。</p>
<p>对以上两个式子进行线性组合，则会有<br />
<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize b_1%28x%29%2AE%5B%5Chat%7Bf%7D_k%28x%29%5D-a_1%28x%29%2AE%5B%5Chat%7Bf%7D_l%28x%29%5D%3D%5Bb_1%28x%29a_0%28x%29-a_1%28x%29b_0%28x%29%5Df%28x%29%2BO%28h%5E2%29" title="b_1(x)*E[\hat{f}_k(x)]-a_1(x)*E[\hat{f}_l(x)]=[b_1(x)a_0(x)-a_1(x)b_0(x)]f(x)+O(h^2)" alt="b_1(x)*E[\hat{f}_k(x)]-a_1(x)*E[\hat{f}_l(x)]=[b_1(x)a_0(x)-a_1(x)b_0(x)]f(x)+O(h^2)" align="absmiddle" /><br />
然后把f(x)的系数移到等式左边，O(h)项的偏差就神奇地消失了。</p>
<p>通过观察核密度估计的表达式，我们可以将上面这个过程等价地认为是对f(x)用了一个新的核函数进行估计，这个新的核函数是<br />
<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize p%28x%29%3D%5Cfrac%7Bb_1%28x%29k%28x%29-a_1%28x%29l%28x%29%7D%7Bb_1%28x%29a_0%28x%29-a_1%28x%29b_0%28x%29%7D" title="p(x)=\frac{b_1(x)k(x)-a_1(x)l(x)}{b_1(x)a_0(x)-a_1(x)b_0(x)}" alt="p(x)=\frac{b_1(x)k(x)-a_1(x)l(x)}{b_1(x)a_0(x)-a_1(x)b_0(x)}" align="absmiddle" /></p>
<p>特别地，如果将l(x)取为x*k(x)，那么p(x)将有一个简单的形式<br />
<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize p%28x%29%3D%5Cfrac%7B%28a_2%28x%29-a_1%28x%29x%29k%28x%29%7D%7Ba_0%28x%29a_2%28x%29-a_1%5E2%28x%29%7D" title="p(x)=\frac{(a_2(x)-a_1(x)x)k(x)}{a_0(x)a_2(x)-a_1^2(x)}" alt="p(x)=\frac{(a_2(x)-a_1(x)x)k(x)}{a_0(x)a_2(x)-a_1^2(x)}" align="absmiddle" /></p>
<p>当x&gt;=h时，这个新的核函数p(x)就是k(x)，而当0&lt;=x&lt;h时（也就是在边界），它会对最初的核函数进行调整。当x&lt;0时，不管算出来的估计值是多少，都只需将密度的估计值取为0即可。</p>
<h2>三、程序实现</h2>
<p>下面这段程序是对本文的第一幅图进行“整容”，代码及效果图如下：</p>
<pre>k=function(x) 3/4*(1-x^2)*(abs(x)&lt;=1);
a0=function(u,h)
{
	lb=-1;
	ub=pmin(u/h,1);
	0.75*(ub-lb)-0.25*(ub^3-lb^3);
}
a1=function(u,h)
{
	lb=-1;
	ub=pmin(u/h,1);
	3/8*(ub^2-lb^2)-3/16*(ub^4-lb^4);
}
a2=function(u,h)
{
	lb=-1;
	ub=pmin(u/h,1);
	0.25*(ub^3-lb^3)-0.15*(ub^5-lb^5);
}
kernel.new=function(x,u,h)
{
	k(x)*(a2(u,h)-a1(u,h)*x)/(a0(u,h)*a2(u,h)-a1(u,h)^2);
}
den.est=function(u,ui,h)
{
	sapply(u,function(u) ifelse(u&lt;0,0,mean(kernel.new((u-ui)/h,u,h))/h));
}
set.seed(123);
dat=rexp(1000,1);
x=seq(0,8,by=0.02);
y=den.est(x,dat,2*bw.nrd0(dat));
plot(x,y,type="l",ylim=c(0,1.2),main="Corrected Kernel");
lines(x,dexp(x,1),col="red");</pre>
<p><a href="http://cos.name/wp-content/uploads/2010/04/kde_corrected_kernel_n1000.png" rel='nofollow'></a></p>
<p><a href="http://cos.name/wp-content/uploads/2010/04/kde_corrected_kernel_n1000.png"><img class="aligncenter size-full wp-image-2081" title="修正核函数（样本量1000）" src="http://cos.name/wp-content/uploads/2010/04/kde_corrected_kernel_n1000.png" alt="" width="500" height="500" / rel='nofollow'></a></p>
<p>从中可以看出，边界的偏差问题已经得到了很好的改进。</p>
<p>如果真实的密度函数的支集不是[0,+∞]，而是某一个闭区间[m,n]，那么偏差修正的过程与上面类似，只不过是要将<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_i%28x%29" title="a_i(x)" alt="a_i(x)" align="absmiddle" />定义为<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a_i%28x%29%3D%5Cint_%7B%28x-n%29%2Fh%7D%5E%7B%28x-m%29%2Fh%7Du%5Eik%28u%29du" title="a_i(x)=\int_{(x-n)/h}^{(x-m)/h}u^ik(u)du" alt="a_i(x)=\int_{(x-n)/h}^{(x-m)/h}u^ik(u)du" align="absmiddle" />。在编程序的时候，也只需把积分的上下限进行相应的调整即可。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/" title="蒙特卡洛方法与定积分计算">蒙特卡洛方法与定积分计算</a> (28)</li><li><a href="http://cos.name/2009/06/why-ratio-estimation-is-more-accurate-in-sampling/" title="比率估计为什么精确">比率估计为什么精确</a> (5)</li><li><a href="http://cos.name/2008/11/probability-theory-origin-development-application/" title="概率论的起源、发展、应用">概率论的起源、发展、应用</a> (5)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >ZUOCHEN</a> : <a class="comment_content" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comment-1576" title="View the entire comment by ZUOCHEN" >膜拜一下，这个方法很好</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comment-1514" title="View the entire comment by 邱怡轩" >a_i(x)不是选出来的，它是对核函数进行积分的结果，积分的上下限与区间的边界有关，参见文中的定义式...</a></li>
<li><a class="commentor" href="" >李皞</a> : <a class="comment_content" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comment-1509" title="View the entire comment by 李皞" >理论虽然如此，但实际操作中a(x)，b(x)都怎么选取？能说说思路吗？
还有p(x)的公式（倒数第...</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comment-1356" title="View the entire comment by 邱怡轩" >这种变换的方法就是把有边界的区间变换到R上吧，比如如果X是[-1,+∞]上的，就令Y=g(X)=lo...</a></li>
<li><a class="commentor" href="http://yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/#comment-1353" title="View the entire comment by 谢益辉" >要是数据有负值呢？</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>蒙特卡洛方法与定积分计算</title>
		<link>http://cos.name/2010/03/monte-carlo-method-to-compute-integration/</link>
		<comments>http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 09:21:23 +0000</pubDate>
		<dc:creator>邓一硕</dc:creator>
				<category><![CDATA[统计计算]]></category>
		<category><![CDATA[Monte-Carlo]]></category>
		<category><![CDATA[定积分]]></category>
		<category><![CDATA[模拟]]></category>
		<category><![CDATA[蒙特卡洛]]></category>

		<guid isPermaLink="false">http://cos.name/?p=2010</guid>
		<description><![CDATA[本文讲述一下蒙特卡洛模拟方法与定积分计算，首先从一个题目开始：设，用蒙特卡洛模拟法求定积分的值。 随机投点法 设服从正方形 上的均匀分布，则可知 分别服从[0,1]上的均匀分布，且相互独立。记事件 ，则的概率为 即定积分 的值 就是事件出现的频率。同时，由伯努利大数定律，我们可以用重复试验中出现的频率作为 的估计值。即将看成是正方形内的随机投点，用随机点落在区域中的频率作为定积分的近似值。这种方法就叫随机投点法，具体做法如下： 图1 随机投点法示意图 1、首先产生服从 上的均匀分布的 个随机数（ 为随机投点个数，可以取很大，如 ）并将其配对。 2、对这对数据 ，记录满足不等式的个数，这就是事件 发生的频数，由此可得事件 发生的频率 ，则 。 举一实例，譬如要计算，模拟次数时，R代码如下： n=10^4; x=runif(n); y=runif(n); f=function(x) { exp(-x^2/2)/sqrt(2*pi) } mu_n=sum(y&#60;f(x)); J=mu_n/n; J 模拟次数 时，令,其余不变。 定积分的精确值和模拟值如下： 表1 精确值 0.3413447 0.342 0.344 0.34187 0.341539 0.341302 注：精确值用integrate(f,0,1)求得 扩展 如果你很细心，你会发现这个 方法目前只适用于积分区间 ，且积分函数 在区间上的取值也位于 内的情况。那么，对于一般区间 上的定积分 呢？一个很明显的思路，如果我们可以将 与 [...]]]></description>
			<content:encoded><![CDATA[<p>本文讲述一下蒙特卡洛模拟方法与定积分计算，首先从一个题目开始：设<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize 0%5Cleq%20f%28x%29%20%5Cleq%201" title="0\leq f(x) \leq 1" alt="0\leq f(x) \leq 1" align="absmiddle" />，用蒙特卡洛模拟法求定积分<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%3D%5Cint_%7B0%7D%5E%7B1%7Df%28x%29dx%20" title="J=\int_{0}^{1}f(x)dx " alt="J=\int_{0}^{1}f(x)dx " align="absmiddle" />的值。</p>
<p style="text-align: center;"><strong>随机投点法</strong></p>
<p>设<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %28X%2CY%29" title="(X,Y)" alt="(X,Y)" align="absmiddle" />服从正方形 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5C%7B0%5Cleq%20x%20%5Cleq%201%2C0%5Cleq%20y%5Cleq%201%5C%7D%20" title="\{0\leq x \leq 1,0\leq y\leq 1\} " alt="\{0\leq x \leq 1,0\leq y\leq 1\} " align="absmiddle" />上的均匀分布，则可知 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize X%2CY" title="X,Y" alt="X,Y" align="absmiddle" />分别服从[0,1]上的均匀分布，且<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize X%2CY" title="X,Y" alt="X,Y" align="absmiddle" />相互独立。记事件<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A%3D%5C%7BY%5Cleq%20f%28X%29%5C%7D" title="A=\{Y\leq f(X)\}" alt="A=\{Y\leq f(X)\}" align="absmiddle" /> ，则<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A%20" title="A " alt="A " align="absmiddle" />的概率为</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize P%28A%29%3DP%28Y%5Cleq%20f%28X%29%29%3D%5Cint_%7B0%7D%5E%7B1%7D%5Cint_%7B0%7D%5E%7Bf%28x%29%7Ddydx%3D%5Cint_%7B0%7D%5E%7B1%7Df%28x%29dx%3DJ%20" title="P(A)=P(Y\leq f(X))=\int_{0}^{1}\int_{0}^{f(x)}dydx=\int_{0}^{1}f(x)dx=J " alt="P(A)=P(Y\leq f(X))=\int_{0}^{1}\int_{0}^{f(x)}dydx=\int_{0}^{1}f(x)dx=J " align="absmiddle" /></p>
<p>即定积分<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J" title="J" alt="J" align="absmiddle" /> 的值 就是事件<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A%20" title="A " alt="A " align="absmiddle" />出现的频率。同时，由伯努利大数定律，我们可以用重复试验中<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A" title="A" alt="A" align="absmiddle" />出现的频率作为 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize p" title="p" alt="p" align="absmiddle" />的估计值。即将<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %28X%2CY%29" title="(X,Y)" alt="(X,Y)" align="absmiddle" />看成是正方形<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5C%7B0%5Cleq%20x%20%5Cleq%201%2C0%5Cleq%20y%20%5Cleq%201%5C%7D" title="\{0\leq x \leq 1,0\leq y \leq 1\}" alt="\{0\leq x \leq 1,0\leq y \leq 1\}" align="absmiddle" />内的随机投点，用随机点落在区域<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %7By%5Cleq%20f%28x%29%7D" title="{y\leq f(x)}" alt="{y\leq f(x)}" align="absmiddle" />中的频率作为定积分的近似值。这种方法就叫随机投点法，具体做法如下：</p>
<p style="text-align: center;"><a rel="attachment wp-att-2051" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/m-6/" rel='nofollow'><img class="size-full wp-image-2051 aligncenter" src="http://cos.name/wp-content/uploads/2010/03/m5.png" alt="" width="480" height="480" / rel='nofollow'></a></p>
<p style="text-align: center;"><a href="../../../../../wp-content/uploads/2010/03/m4.png" rel='nofollow'></a>图1 随机投点法示意图</p>
<p>1、首先产生服从 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D" title="[0,1]" alt="[0,1]" align="absmiddle" />上的均匀分布的 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize 2n%20" title="2n " alt="2n " align="absmiddle" />个随机数（ <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%20" title="n " alt="n " align="absmiddle" />为随机投点个数，可以取很大，如 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%3D10%5E4%20" title="n=10^4 " alt="n=10^4 " align="absmiddle" />）并将其配对。</p>
<p>2、对这<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n" title="n" alt="n" align="absmiddle" />对数据 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %28x_i%2Cy_i%29%2Ci%3D1%2C2%2C...%2Cn" title="(x_i,y_i),i=1,2,...,n" alt="(x_i,y_i),i=1,2,...,n" align="absmiddle" /> ，记录满足不等式<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize y_i%5Cleq%20f%28x_i%29%20" title="y_i\leq f(x_i) " alt="y_i\leq f(x_i) " align="absmiddle" />的个数，这就是事件 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A%20" title="A " alt="A " align="absmiddle" />发生的频数<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cmu_n" title="\mu_n" alt="\mu_n" align="absmiddle" />，由此可得事件<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize A%20" title="A " alt="A " align="absmiddle" /> 发生的频率<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cfrac%7B%5Cmu_n%7D%7Bn%7D%20" title="\frac{\mu_n}{n} " alt="\frac{\mu_n}{n} " align="absmiddle" /> ，则<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%5Capprox%20%5Cfrac%7B%5Cmu_n%7D%20%7Bn%7D" title="J\approx \frac{\mu_n} {n}" alt="J\approx \frac{\mu_n} {n}" align="absmiddle" /> 。</p>
<p>举一实例，譬如要计算<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cint_%7B0%7D%5E%7B1%7De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7Ddx%20" title="\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " alt="\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " align="absmiddle" />，模拟次数<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%3D10%5E4" title="n=10^4" alt="n=10^4" align="absmiddle" />时，R代码如下：</p>
<pre>n=10^4;
 x=runif(n);
 y=runif(n);
 f=function(x)
 {
 exp(-x^2/2)/sqrt(2*pi)
 }
 mu_n=sum(y&lt;f(x));
 J=mu_n/n;
 J</pre>
<p>模拟次数 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%3D10%5E5%20" title="n=10^5 " alt="n=10^5 " align="absmiddle" />时，令<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%3D10%5E5" title="n=10^5" alt="n=10^5" align="absmiddle" />,其余不变。</p>
<p>定积分<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cint_%7B0%7D%5E%7B1%7De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7Ddx%20" title="\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " alt="\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " align="absmiddle" />的精确值和模拟值如下：</p>
<p>表1</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top">精确值</td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E3" title="  10^3" alt="  10^3" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E4" title="  10^4" alt="  10^4" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E5" title="  10^5" alt="  10^5" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E6" title="  10^6" alt="  10^6" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E7" title="  10^7" alt="  10^7" align="absmiddle" /></td>
</tr>
<tr>
<td valign="top">0.3413447</td>
<td valign="top">0.342</td>
<td valign="top">0.344</td>
<td valign="top">0.34187</td>
<td valign="top">0.341539</td>
<td valign="top">0.341302</td>
</tr>
</tbody>
</table>
<pre>注：精确值用integrate(f,0,1)求得</pre>
<p>扩展</p>
<p>如果你很细心，你会发现这个 方法目前只适用于积分区间<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D%20" title="[0,1] " alt="[0,1] " align="absmiddle" /> ，且积分函数 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28x%29%20" title="f(x) " alt="f(x) " align="absmiddle" />在区间<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D" title="[0,1]" alt="[0,1]" align="absmiddle" />上的取值也位于 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D" title="[0,1]" alt="[0,1]" align="absmiddle" /> 内的情况。那么，对于一般区间 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Ba%2Cb%5D%20" title="[a,b] " alt="[a,b] " align="absmiddle" />上的定积分<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%3D%5Cint_%7Ba%7D%5E%7Bb%7Dg%28x%29dx%20" title="J&#039;=\int_{a}^{b}g(x)dx " alt="J&#039;=\int_{a}^{b}g(x)dx " align="absmiddle" /> 呢？一个很明显的思路，如果我们可以将 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%20" title="J&#039; " alt="J&#039; " align="absmiddle" /> 与<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J" title="J" alt="J" align="absmiddle" /> 建立代数关系就可以了。</p>
<p>首先，做线性变换，令 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize y%3D%28x-a%29%2F%28b-a%29%20" title="y=(x-a)/(b-a) " alt="y=(x-a)/(b-a) " align="absmiddle" /> ，此时，</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize x%3D%28b-a%29y%2Ba" title="x=(b-a)y+a" alt="x=(b-a)y+a" align="absmiddle" />,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%3D%28b-a%29%5Cint_%7B0%7D%5E%7B1%7Dg%5B%28b-a%29y%2Ba%5Ddy%20" title="J&#039;=(b-a)\int_{0}^{1}g[(b-a)y+a]dy " alt="J&#039;=(b-a)\int_{0}^{1}g[(b-a)y+a]dy " align="absmiddle" />。</p>
<p>进一步如果在区间<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Ba%2Cb%5D%20" title="[a,b] " alt="[a,b] " align="absmiddle" />上有<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize c%5Cleq%20g%28x%29%20%5Cleq%20d%20" title="c\leq g(x) \leq d " alt="c\leq g(x) \leq d " align="absmiddle" /> ，令</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28y%29%3D%5Cfrac%7B1%7D%7Bd-c%7D%7Bg%28x%29-c%7D%3D%5Cfrac%7B1%7D%7Bd-c%7D%7Bg%5Ba%2B%28b-a%29y%5D-c%7D%20" title="f(y)=\frac{1}{d-c}{g(x)-c}=\frac{1}{d-c}{g[a+(b-a)y]-c} " alt="f(y)=\frac{1}{d-c}{g(x)-c}=\frac{1}{d-c}{g[a+(b-a)y]-c} " align="absmiddle" />，</p>
<p>则<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize 0%5Cleq%20f%28y%29%20%5Cleq%201" title="0\leq f(y) \leq 1" alt="0\leq f(y) \leq 1" align="absmiddle" />。此时，可以得到<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%3D%5Cint_%7Ba%7D%5E%7Bb%7Dg%28x%29dx%3DS_0J%2Bc%28b-a%29%20" title="J&#039;=\int_{a}^{b}g(x)dx=S_0J+c(b-a) " alt="J&#039;=\int_{a}^{b}g(x)dx=S_0J+c(b-a) " align="absmiddle" /> 。</p>
<p>其中,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize S_0%3D%28b-a%29%28d-c%29%20" title="S_0=(b-a)(d-c) " alt="S_0=(b-a)(d-c) " align="absmiddle" />,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%3D%5Cint_%7B0%7D%5E%7B1%7Df%28y%29dy%20" title="J=\int_{0}^{1}f(y)dy " alt="J=\int_{0}^{1}f(y)dy " align="absmiddle" />。</p>
<p>这说明，用随机投点法计算定积分方法具有普遍意义。</p>
<p>举一个实例，求定积分 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%3D%5Cint_%7B2%7D%5E%7B5%7De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7Ddx%20" title="J&#039;=\int_{2}^{5}e^{-x^2/2}/\sqrt{2\pi}dx " alt="J&#039;=\int_{2}^{5}e^{-x^2/2}/\sqrt{2\pi}dx " align="absmiddle" />。</p>
<p>显然<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize a%3D2%2Cb%3D5%20" title="a=2,b=5 " alt="a=2,b=5 " align="absmiddle" />，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize c%3Dmin%5C%7Bg%28x%29%7C2%5Cleq%20x%20%5Cleq%205%5C%7D%2Cd%3Dmax%5C%7Bg%28x%29%7C2%5Cleq%20x%20%5Cleq%205%5C%7D%20" title="c=min\{g(x)|2\leq x \leq 5\},d=max\{g(x)|2\leq x \leq 5\} " alt="c=min\{g(x)|2\leq x \leq 5\},d=max\{g(x)|2\leq x \leq 5\} " align="absmiddle" />，由于<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize g%28x%29%3De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7D%20" title="g(x)=e^{-x^2/2}/\sqrt{2\pi} " alt="g(x)=e^{-x^2/2}/\sqrt{2\pi} " align="absmiddle" />在 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B2%2C5%5D" title="[2,5]" alt="[2,5]" align="absmiddle" />上时单调减函数，所以<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize c%3Dg%285%29%2Cd%3Dg%282%29" title="c=g(5),d=g(2)" alt="c=g(5),d=g(2)" align="absmiddle" /> ，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize S_0%3D%28b-a%29%28d-c%29%20" title="S_0=(b-a)(d-c) " alt="S_0=(b-a)(d-c) " align="absmiddle" />。R中代码为</p>
<pre>a=2;
 b=5;
 g=function(x)
 {
 exp(-x^2/2)/sqrt(2*pi);
 }
 f=function(y)
 {
 (g(a+(b-a)*y)-c)/(d-c);
 }
 c=g(5);d=g(2);s_0=(b-a)*(d-c);
 n=10^4;
 x=runif(n);y=runif(n);
 mu_n=sum(y&lt;=f(x));
 J=mu_n/n;
 J_0=s_0*J+c*(b-a);</pre>
<p>定积分 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%27%3D%5Cint_%7B2%7D%5E%7B5%7De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7Ddx%20" title="J&#039;=\int_{2}^{5}e^{-x^2/2}/\sqrt{2\pi}dx " alt="J&#039;=\int_{2}^{5}e^{-x^2/2}/\sqrt{2\pi}dx " align="absmiddle" />的精确值和模拟值如下：</p>
<p>表2</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top">真实值</td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E3" title="  10^3" alt="  10^3" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize 10%5E4" title="10^4" alt="10^4" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E5" title="  10^5" alt="  10^5" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E6" title="  10^6" alt="  10^6" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E7" title="  10^7" alt="  10^7" align="absmiddle" /></td>
</tr>
<tr>
<td valign="top">0.02274985</td>
<td valign="top">0.02332792</td>
<td valign="top">0.02311736</td>
<td valign="top">0.02262659</td>
<td valign="top">0.02284152</td>
<td valign="top">0.02278524</td>
</tr>
</tbody>
</table>
<pre>注：精确值用integrate(g,2,5)求得)</pre>
<p>平均值法</p>
<p>蒙特卡洛模拟法计算定积分时还有另一种方法，叫平均值法。这个原理也很简单：设随机变量 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize X%20" title="X " alt="X " align="absmiddle" />服从<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D%20" title="[0,1] " alt="[0,1] " align="absmiddle" />上的均匀分布，则 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize Y%3Df%28X%29" title="Y=f(X)" alt="Y=f(X)" align="absmiddle" />的数学期望为</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize E%28f%28X%29%29%3D%5Cint_%7B0%7D%5E%7B1%7Df%28x%29dx%3DJ%20" title="E(f(X))=\int_{0}^{1}f(x)dx=J " alt="E(f(X))=\int_{0}^{1}f(x)dx=J " align="absmiddle" /></p>
<p>所以估计<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%20" title="J " alt="J " align="absmiddle" /> 的值就是估计 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28X%29" title="f(X)" alt="f(X)" align="absmiddle" />的数学期望值。由辛钦大数定律，可以用<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28X%29" title="f(X)" alt="f(X)" align="absmiddle" /> 的观察值的均值取估计<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28X%29" title="f(X)" alt="f(X)" align="absmiddle" /> 的数学期望。具体做法：</p>
<p>先用计算机产生<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n" title="n" alt="n" align="absmiddle" /> 个服从<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5B0%2C1%5D%20" title="[0,1] " alt="[0,1] " align="absmiddle" />上均匀分布的随机数：<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize x_i%2Ci%3D1%2C2%2C...%2Cn%20" title="x_i,i=1,2,...,n " alt="x_i,i=1,2,...,n " align="absmiddle" /> 。</p>
<p>对每一个<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize x_i" title="x_i" alt="x_i" align="absmiddle" /> ，计算<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28x_i%29" title="f(x_i)" alt="f(x_i)" align="absmiddle" /> 。</p>
<p>计算<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%5Capprox%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7Df%28x_i%29%20" title="J\approx \frac{1}{n}\sum_{i=1}^{n}f(x_i) " alt="J\approx \frac{1}{n}\sum_{i=1}^{n}f(x_i) " align="absmiddle" />。</p>
<p>譬如，计算 <img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize J%3D%5Cint_%7B0%7D%5E%7B1%7De%5E%7B-x%5E2%2F2%7D%2F%5Csqrt%7B2%5Cpi%7Ddx%20" title="J=\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " alt="J=\int_{0}^{1}e^{-x^2/2}/\sqrt{2\pi}dx " align="absmiddle" />，R中的代码为</p>
<pre>n=10^4;
 x=runif(n);
 f=function(x)
 {
 exp(-x^2/2)/sqrt(2*pi)
 }
 J=mean(f(x));</pre>
<p>其精确值和模拟值如下：<br />
表3</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top">真实值</td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E3" title="  10^3" alt="  10^3" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E4" title="  10^4" alt="  10^4" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E5" title="  10^5" alt="  10^5" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E6" title="  10^6" alt="  10^6" align="absmiddle" /></td>
<td valign="top"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %20%2010%5E7" title="  10^7" alt="  10^7" align="absmiddle" /></td>
</tr>
<tr>
<td valign="top">0.3413447</td>
<td valign="top">0.3405831</td>
<td valign="top">0.3410739</td>
<td valign="top">0.3414443</td>
<td valign="top">0.3414066</td>
<td valign="top">0.3413366</td>
</tr>
</tbody>
</table>
<p>平均值法与随机投点法类似可以进行扩展，这里不再赘述。</p>
<p style="text-align: center;"><strong>结论</strong></p>
<p>用蒙特卡洛模拟法计算定积分具有普遍意义。蒙特卡洛模拟方法为我们提供了一个看待世界的新思路，即一个不具随机性的事件可以通过一定的方法用随机事件来模拟或逼近。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/04/kernel-density-estimation-with-unbounded-region/" title="有边界区间上的核密度估计">有边界区间上的核密度估计</a> (10)</li><li><a href="http://cos.name/2009/06/why-ratio-estimation-is-more-accurate-in-sampling/" title="比率估计为什么精确">比率估计为什么精确</a> (5)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >huang shuai</a> : <a class="comment_content" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comment-1392" title="View the entire comment by huang shuai" >http://www.stat.columbia.edu/~cook/movabletype/mlm...</a></li>
<li><a class="commentor" href="http://yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comment-1306" title="View the entire comment by 谢益辉" >那要看怎么理解“对维数不敏感”了，如果只是“不限制维数”的话，那这算不上优点，因为高维情况下需要的样...</a></li>
<li><a class="commentor" href="" >胡荣兴</a> : <a class="comment_content" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comment-1305" title="View the entire comment by 胡荣兴" >很久之前用过蒙特卡罗方法，现在都生疏了。蒙特卡罗的好处就是计算简化，不用去考虑那么复杂的积分或微分甚...</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comment-1272" title="View the entire comment by 邱怡轩" >set.seed()不是为了防止产生相同的随机数，相反，正是为了产生相同的随机数，因为这样一来，每次...</a></li>
<li><a class="commentor" href="" >colinisstudent</a> : <a class="comment_content" href="http://cos.name/2010/03/monte-carlo-method-to-compute-integration/#comment-1270" title="View the entire comment by colinisstudent" >我倒是觉得并不是所有的积分问题都值得硬上的，一些问题能够被简化，使得积分问题在相对比较低维的情况下进...</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2010/03/monte-carlo-method-to-compute-integration/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>也谈提高R语言的运算效率</title>
		<link>http://cos.name/2009/12/improve-r-computation-efficiency/</link>
		<comments>http://cos.name/2009/12/improve-r-computation-efficiency/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 08:38:22 +0000</pubDate>
		<dc:creator>谢益辉</dc:creator>
				<category><![CDATA[统计计算]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[C语言]]></category>
		<category><![CDATA[P值]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[R语言]]></category>
		<category><![CDATA[t检验]]></category>
		<category><![CDATA[向量]]></category>
		<category><![CDATA[显式循环]]></category>
		<category><![CDATA[隐式循环]]></category>

		<guid isPermaLink="false">http://cos.name/?p=1796</guid>
		<description><![CDATA[用过底层语言做计算的人转入R语言的时候一般都会觉得R语言的运算太慢，这是一个常见的对R的误解或者对R的设计的不理解。在二三十年前Chambers等一群人在贝尔实验室设计S语言之前，统计计算主要是通过那些底层语言实现的，典型的如Fortran。当时有一个基于Fortran的统计分析库，用它的麻烦就在于无论做什么样的数据分析，都涉及到一大摞繁琐的底层代码，这让数据分析变得很没劲，统计学家有统计学家的事情，天天陷在计算机程序代码中也不是个办法，要摆脱底层语言，那就只能设计高层语言了。有所得必有所失，众所周知，高层语言一般来说比底层语言低效，但对用户来说更友好。举个简单的例子，用C语言计算均值时，我们得对一个向量（数组）从头循环到尾把每个值累加起来，得到总和，然后除以向量的长度，而均值在统计当中简直是再家常便饭不过了，要是每次都要来这么个循环，大家也都甭干活儿了，天天写循环好了。 前两天COS论坛上有个帖子提到“R语言的执行效率问题”，大意如下： 有120000行数据，用perl写成12万行R命令做t.test，然后执行，大概几分钟就算完了。如果只用R语言，把所有数据先读入，然后用循环，每一行做t.test，花了几个小时，到现在还没有算完。这说明一个问题，在R里执行单行命令要比用循环快，涉及到循环的问题，最好写成单行命令执行。 我不清楚作者是如何写这“12万行”R命令的，本文假设是把t.test(dat[i, ]), i = 1, 2, ..., 120000写入一个文件，然后用source()执行之。面对这样一个问题，我们有若干种改进计算的可能性。首先我们看“硬”写入程序代码的方法： ## 为了使计算可重复，设定随机数种子 set.seed(123) ## 生成数据，随机数，120000行 x 100列矩阵 dat = matrix(rnorm(120000 * 100), 120000) nr = nrow(dat) nc = ncol(dat) ## 六种方法的P值向量 p1 = p2 = p3 = p4 = p5 = p6 = numeric(nr) ## via source() f = file("test.t") writeLines(sprintf("p1[%d] = t.test(dat[%d, ])$p.value", [...]]]></description>
			<content:encoded><![CDATA[<p>用过底层语言做计算的人转入R语言的时候一般都会觉得R语言的运算太慢，这是一个常见的对R的误解或者对R的设计的不理解。在二三十年前Chambers等一群人在贝尔实验室设计S语言之前，统计计算主要是通过那些底层语言实现的，典型的如Fortran。当时有一个基于Fortran的统计分析库，用它的麻烦就在于无论做什么样的数据分析，都涉及到一大摞繁琐的底层代码，这让数据分析变得很没劲，统计学家有统计学家的事情，天天陷在计算机程序代码中也不是个办法，要摆脱底层语言，那就只能设计高层语言了。有所得必有所失，众所周知，高层语言一般来说比底层语言低效，但对用户来说更友好。举个简单的例子，用C语言计算均值时，我们得对一个向量（数组）从头循环到尾把每个值累加起来，得到总和，然后除以向量的长度，而均值在统计当中简直是再家常便饭不过了，要是每次都要来这么个循环，大家也都甭干活儿了，天天写循环好了。</p>
<p>前两天COS论坛上有个帖子提到“<a title="http://cos.name/bbs/read.php?tid=17601" href="http://cos.name/bbs/read.php?tid=17601" target="_blank" rel='nofollow'>R语言的执行效率问题</a>”，大意如下：</p>
<blockquote><p>有120000行数据，用perl写成12万行R命令做t.test，然后执行，大概几分钟就算完了。如果只用R语言，把所有数据先读入，然后用循环，每一行做t.test，花了几个小时，到现在还没有算完。这说明一个问题，在R里执行单行命令要比用循环快，涉及到循环的问题，最好写成单行命令执行。</p></blockquote>
<p>我不清楚作者是如何写这“12万行”R命令的，本文假设是把<code>t.test(dat[i, ]), i = 1, 2, ..., 120000</code>写入一个文件，然后用<code>source()</code>执行之。面对这样一个问题，我们有若干种改进计算的可能性。首先我们看“硬”写入程序代码的方法：</p>
<pre>## 为了使计算可重复，设定随机数种子
set.seed(123)
## 生成数据，随机数，120000行 x 100列矩阵
dat = matrix(rnorm(120000 * 100), 120000)
nr = nrow(dat)
nc = ncol(dat)
## 六种方法的P值向量
p1 = p2 = p3 = p4 = p5 = p6 = numeric(nr)

## via source()
f = file("test.t")
writeLines(sprintf("p1[%d] = t.test(dat[%d, ])$p.value",
    seq(nr), seq(nr)), f)
system.time({
    source(f)
})
#   user  system elapsed
#  95.36    0.19   95.86
close(f)
unlink("test.t")</pre>
<h1>1、向量式计算：<code>apply()</code>以及<code>*apply()</code></h1>
<p>当我们需要对矩阵的行或者列逐一计算时，<code>apply()</code>系列函数可能会提高效率。本例是对矩阵的行做t检验，那么可以这样计算：</p>
<pre>## via apply()
system.time({
    p2 = apply(dat, 1, function(x) {
        t.test(x)$p.value
    })
})
#   user  system elapsed
#  63.12    0.06   63.50
identical(p1, p2)
# [1] TRUE</pre>
<p>结果比第一种方法快了大约半分钟，而且计算结果完全一样。<code>apply()</code>本质上仍然是循环，但它在某些情况下比直接用显式循环要快：</p>
<pre>## via for-loop
system.time({
    for (i in seq(nr)) p3[i] = t.test(dat[i, ])$p.value
})
#   user  system elapsed
#  69.88    0.03   70.05
identical(p2, p3)
# [1] TRUE</pre>
<p>不过<code>apply()</code>系列函数在提高运算速度上优势并不会太明显，提倡用它的原因是它和统计中的矩阵运算相似，可以简化代码，相比起<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Csum_%7Bi%3D1%7D%5En%20x_i%2Fn" title="\sum_{i=1}^n x_i/n" alt="\sum_{i=1}^n x_i/n" align="absmiddle" />，我们可能更愿意看<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cbar%7Bx%7D" title="\bar{x}" alt="\bar{x}" align="absmiddle" />这样的表达式。很多R内置函数都是用底层语言写的，我们需要做的就是把一个对象作为整体传给函数去做计算，而不要自行把对象分解为一个个小部分计算，这个例子可能更能体现向量式计算的思想：</p>
<pre>system.time(apply(dat, 1, mean))
#   user  system elapsed
#   5.28    0.04    5.25
system.time({
    x = numeric(nr)
    for (i in 1:nr) x[i] = mean(dat[i, ])
})
#   user  system elapsed
#   4.44    0.02    4.42
system.time(rowMeans(dat))
#   user  system elapsed
#   0.11    0.00    0.13</pre>
<h1>2、明确计算的目的</h1>
<p>很多情况下，R函数返回的不仅仅是一个数字作为结果，而是会得到一系列诸如统计量、P值、各种系数等对象，在我们调用R函数之前如果能想清楚我们究竟需要什么，也许对计算的速度提升有帮助。比如本例中，也许我们仅需要12万个双边P值，其它数字我们都用不着，那么可以考虑“手工”计算P值：</p>
<pre>## "hand" calculation in R
system.time({
    p4 = 2 * pt(apply(dat, 1, function(x, mu = 0) -abs((mean(x) -
        mu)/sqrt(var(x)/nc))), nc - 1)
})
#   user  system elapsed
#  15.97    0.07   16.08
identical(p3, p4)
# [1] TRUE</pre>
<p>上面的计算更“纯净”，所以计算速度有了本质的提升，而且计算的结果和前面毫无差异。在做计算之前，人的脑子多思考一分钟，也许计算机的“脑子”会少转一个小时。</p>
<h1>3、把四则运算交给底层语言</h1>
<p>R是高层语言，把它拿来做简单的四则运算是很不划算的，而且容易导致程序低效。加加减减的活儿是C和Fortran等底层语言的强项，所以可以交给它们去做。以下我们用一段C程序来计算t统计量，然后用<code>R CMD SHLIB</code>将它编译为<code>dll</code>（Windows）或<code>so</code>（Linux）文件，并加载到R中，用<code>.C()</code>调用，最终用R函数<code>pt()</code>计算P值：</p>
<pre>## "hand" calculation in C for t-statistic
writeLines("#include &lt;math.h&gt;

void calc_tstat(double *x, int *nr, int *nc, double *mu, double *tstat)
{
    int i, j;
    double sum = 0.0, sum2 = 0.0, mean, var;
    for (i = 0; i &lt; *nr; i++) {
        for (j = 0; j &lt; *nc; j++) {
            sum += x[i + j * *nr];
        }
        mean = sum / (double) *nc;
        sum = 0.0;
        for (j = 0; j &lt; *nc; j++) {
            sum2 += (x[i + j * *nr] - mean) * (x[i + j * *nr] - mean);
        }
        var = sum2 / (double) (*nc - 1);
        sum2 = 0.0;
        tstat[i] = (mean - *mu) / sqrt(var / (*nc - 1));
    }
}", "calc_tstat.c")
system("R CMD SHLIB calc_tstat.c")
dyn.load(sprintf("calc_tstat%s", .Platform$dynlib.ext))
system.time({
    p5 = 2 * pt(-abs(.C("calc_tstat", as.double(dat), nr, nc,
        0, double(nrow(dat)))[[5]]), nc - 1)
})
#   user  system elapsed
#   0.86    0.06    0.92
dyn.unload(sprintf("calc_tstat%s", .Platform$dynlib.ext))</pre>
<p>因为R可以用<code>system()</code>调用系统命令，所以整个过程全都可以用R完成，Windows用户需要安装<a title="http://www.murdoch-sutherland.com/Rtools/" href="http://www.murdoch-sutherland.com/Rtools/" target="_blank" rel='nofollow'>Rtools</a>并设置系统环境变量<code>PATH</code>才能使用<code>R CMD SHLIB</code>。</p>
<p>更进一步，因为R自身的一些C程序也是可供用户的C程序调用的，所以我们可以把整个P值的计算过程全都扔进C代码中，一步完成：</p>
<pre>## "hand" calculation in C calling Rmath.h
writeLines("#include &lt;Rmath.h&gt;
void calc_pvalue(double *x, int *nr, int *nc, double *mu, double *pval)
{
    int i, j;
    double sum = 0.0, sum2 = 0.0, mean, var;
    for (i = 0; i &lt; *nr; i++) {
        for (j = 0; j &lt; *nc; j++) {
            sum += x[i + j * *nr];
        }
        mean = sum / (double) *nc;
        sum = 0.0;
        for (j = 0; j &lt; *nc; j++) {
            sum2 += (x[i + j * *nr] - mean) * (x[i + j * *nr] - mean);
        }
        var = sum2 / (double) (*nc - 1);
        sum2 = 0.0;
        pval[i] = 2 * pt(-fabs((mean - *mu) / sqrt(var / (*nc - 1))),
                      (double) (*nc - 1), 1, 0);
    }
}", "calc_pvalue.c")
system("R CMD SHLIB calc_pvalue.c")
dyn.load(sprintf("calc_pvalue%s", .Platform$dynlib.ext))
system.time({
    p6 = .C("calc_pvalue", as.double(dat), nr, nc, as.double(0),
        double(nrow(dat)))[[5]]
})
#   user  system elapsed
#   0.83    0.07    0.91
dyn.unload(sprintf("calc_pvalue%s", .Platform$dynlib.ext))</pre>
<p>头文件<code>Rmath.h</code>的引入使得我们可以调用很多基于C程序的R函数，详情参考手册Writing R Extensions。通过C计算出来的P值和前面用R算的略有差异，下面画出<code>p6 - p1</code> vs <code>p1</code>以及<code>p6 - p5</code> vs <code>p5</code>的图：</p>
<div id="attachment_1802" class="wp-caption aligncenter" style="width: 490px"><a href="http://cos.name/wp-content/uploads/2009/12/p-values-error.png" rel='nofollow'><img class="size-full wp-image-1802" title="P值的差异" src="http://cos.name/wp-content/uploads/2009/12/p-values-error.png" alt="P值的差异" width="480" height="480" /></a><p class="wp-caption-text">P值的差异</p></div>
<p>导致差异的原因此处不细究，感兴趣的读者可以帮忙检查一下。</p>
<h1>小结</h1>
<ol>
<li>若你熟悉底层语言，计算又不太复杂，那么可用底层语言写，然后用R调之；</li>
<li>否则把R对象当做整体去计算，能做<code>x + 1</code>就不要做<code>for (i in length(x)) x[i] + 1</code></li>
<li>不要低估R core们的编程水平，他们已经做了很多工作让用户脱离底层编程</li>
</ol>
<p>注：本文中的运算时间可能不可重复，这与计算机所处的状态有关，但大体来说，运算速度的快慢是可以肯定的。本文仅仅是关于统计计算的一个微小的例子，以后若有更好的例子，可能会更新本文；也欢迎各位提供更多示例。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/07/maximum-likelihood-estimation-in-r/" title="R中的极大似然估计">R中的极大似然估计</a> (2)</li><li><a href="http://cos.name/2009/03/scatterplot-matrix-visualization/" title="不同版本的散点图矩阵">不同版本的散点图矩阵</a> (17)</li><li><a href="http://cos.name/2009/03/correlation-matrix-visualization/" title="相关矩阵的可视化及其新方法探究">相关矩阵的可视化及其新方法探究</a> (41)</li><li><a href="http://cos.name/2009/03/parallel-coordinates-and-andrews-curve/" title="调和曲线图和轮廓图的比较">调和曲线图和轮廓图的比较</a> (12)</li><li><a href="http://cos.name/2009/01/r-and-sas-new-york-times/" title="R与SAS之争：一个导读">R与SAS之争：一个导读</a> (28)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="http://" >刘重杰</a> : <a class="comment_content" href="http://cos.name/2009/12/improve-r-computation-efficiency/#comment-1312" title="View the entire comment by 刘重杰" >简单来说，R底层基本上都是C做的，调用的库也是久经考验的。
程序运行的效率核心在于对语言提供的功能...</a></li>
<li><a class="commentor" href="" >zong0jie</a> : <a class="comment_content" href="http://cos.name/2009/12/improve-r-computation-efficiency/#comment-1209" title="View the entire comment by zong0jie" >补充一点，系统是xp sp3。 类似测试在fedora 12下也进行过，结果依然类似。</a></li>
<li><a class="commentor" href="" >zong0jie</a> : <a class="comment_content" href="http://cos.name/2009/12/improve-r-computation-efficiency/#comment-1208" title="View the entire comment by zong0jie" >在R2.10里面貌似循环速度大大加快，只比apply慢了300%，几分钟时间完全可以接受了。
我机...</a></li>
<li><a class="commentor" href="" >yfyang</a> : <a class="comment_content" href="http://cos.name/2009/12/improve-r-computation-efficiency/#comment-1139" title="View the entire comment by yfyang" >用R做像EM之类的处理通常很痛苦。问题就在循环、四则运算、拷贝等问题上面。因为R语言是变量和LISP...</a></li>
<li><a class="commentor" href="http://yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/12/improve-r-computation-efficiency/#comment-1099" title="View the entire comment by 谢益辉" >哦，谢谢相告，我之前还搜了好半天邮件，人名和ID对不起来了。也谢谢lyxmoo的热心支持！</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/12/improve-r-computation-efficiency/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>浅谈Buffon投针问题及其推广</title>
		<link>http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/</link>
		<comments>http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 09:04:09 +0000</pubDate>
		<dc:creator>魏太云</dc:creator>
				<category><![CDATA[统计计算]]></category>
		<category><![CDATA[Buffon投针]]></category>
		<category><![CDATA[几何概率]]></category>
		<category><![CDATA[期望]]></category>
		<category><![CDATA[概率论]]></category>

		<guid isPermaLink="false">http://cos.name/?p=1627</guid>
		<description><![CDATA[公元1777年，法国科学家D·布丰(D.Buffon 1707～1788)设计了一个巧夺天工的实验：往间距为a的平行线族之间投掷长为L 的针，可以计算出针和平行线相交的概率。]]></description>
			<content:encoded><![CDATA[<p><a href="http://cos.name/wp-content/uploads/2009/11/semicircle2.gif" rel='nofollow'><img class="alignleft size-thumbnail wp-image-1792" title="semicircle2" src="http://cos.name/wp-content/uploads/2009/11/semicircle2-150x150.gif" alt="semicircle2" width="150" height="150" /></a>公元1777年，法国科学家D·布丰(D.Buffon 1707～1788)设计了一个巧夺天工的实验：往间距为a的平行线族之间投掷长为L 的针，可以计算出针和平行线相交的概率为：<br />
<img class="aligncenter size-full wp-image-420" title="pi_2ltopia" src="http://taiyun.cos.name/wp-content/uploads/2009/11/pi_2ltopia.png" alt="pi_2ltopia" width="85" height="46" /><br />
根据此式，可以得到pi的近似估计值，这的确是一个伟大的、奇妙而划时代的实验，可算是蒙特卡罗模拟中的鼻祖和经典了。在大多数教材上，这个概率都是用积分或二重积分计算得来的，比较繁琐，在<a href="http://www.matrix67.com/blog/archives/2494" rel='nofollow'>matrix67的博客</a>中，我欣慰而惊奇地看到了一种非常简便、直观的解法，感慨了一番，也稍微思考了一番。</p>
<blockquote><p>期望值的一个最引人注目的性质就是，E(A+B)=E(A)+E(B)，不管A和B是不是独立的。想象一根长度为L的铁丝，不管它被弯成了什么形状，扔到地上后它与地板上的平行线的交点个数的期望值都是一样的，并且这个值是和L成正比的。这是因为，我们可以把一根弯铁丝看作很多很多小的直线段构成；而每个充分小的直线段与平行线交点个数的期望都是相同的，那么由期望值的线性关系，整个弯铁丝与平行线交点数的期望就是c·L，其中c是某个固定的系数。为了求出这个系数是多少，我们只需要考虑一些特殊的情况。注意到，把一根长度为pi的铁丝弯成一个直径为1的圆，则把它扔到地上之后，它与这组平行线总有两个交点。这就是说，pi的c倍就等于2，即c等于2/pi。自然，一根单位长度的针与平行线的交点个数的期望值就是2/pi；而由于这根针与平行线要么没有交点，要么就只有一个交点，因此这个数值就相当于是针与平行线相交的概率了。——matrix67</p></blockquote>
<p><span id="more-1627"></span>matrix67是北大中文系的学生，他对数学思维的把握令我十分汗颜。期望的这条性质大家知道，但是离灵活运用却差得很远。根据上述理论，很容易得到，对于任何曲线，它和平行线族交点个数(Y)的期望都是：<br />
<img class="aligncenter size-full wp-image-422" title="pi_2stopia" src="http://taiyun.cos.name/wp-content/uploads/2009/11/pi_2stopia.png" alt="pi_2stopia" width="117" height="49" /></p>
<p>其中S是该曲线周长。</p>
<p>如果要向平行线族之间投掷凸n边形（或者扩展到凸域，凸域就是过该图形任一点做切线，那么所有的点都在切线的同侧，也就是没有凹进去的部分），如果这个凸域的直径不大于平行线距离a的话，那么它和平行线族相交的概率为：</p>
<p><img class="aligncenter size-full wp-image-423" title="P_stopia" src="http://taiyun.cos.name/wp-content/uploads/2009/11/P_stopia.png" alt="P_stopia" width="90" height="52" /></p>
<p>其中，S为凸区域的周长。<br />
概率值刚好是交点个数期望的一半，这个也很直观，因为凸域和平行线的交点个数只有三种可能：</p>
<ol>
<li>1个交点：当凸域和平行线相切，或者顶点重合</li>
<li>2个交点：这种情况是最常见的</li>
<li>无穷多个交点：有一边重合的时候</li>
</ol>
<p>其中，第一种情况和第三种情况的几何概率为零，故概率值刚好是交点个数期望的一半(这里不太严谨，望大家指教)。把两根针并在一起，既可以构造一个闭区域，其与平行线相交的概率和交点个数都和上面理论一致。</p>
<p>如果投掷一般闭合区域的话，那么它和平行线族相交的概率依然为：</p>
<p><img class="aligncenter size-full wp-image-423" title="P_stopia" src="http://taiyun.cos.name/wp-content/uploads/2009/11/P_stopia.png" alt="P_stopia" width="90" height="52" /></p>
<p>不过，此时S为该闭区域所生成的最小凸区域的周长。</p>
<p>因为尽管它们的周长不一样，和平行线交点的期望不一样，但是它们和平行线是否有交点的概率是一样的。下图中的类半圆图形就是月牙图形生成的最小凸区域，它们显然和平行线是否相交完全等价。</p>
<p><a href="http://cos.name/wp-content/uploads/2009/11/semicircle2.gif" rel='nofollow'><img class="aligncenter size-full wp-image-1792" src="http://cos.name/wp-content/uploads/2009/11/semicircle2.gif" alt="" width="423" height="211" /></a></p>
<p>最后，要说的是直观思维的重要性，定理有千千万万，如果能用直观的形式将它们逐渐消化，那是最好不过的了，我在看书的时候经常能把一个定理啃下来，但是还是觉得对这个定理依然云里雾里的。对此，<a href="http://www.matrix67.com/blog/archives/2494" rel='nofollow'>matrix67</a>做了很精彩的评价：</p>
<blockquote><p>数学学习真正悲哀的就是，记住了某个神奇而伟大的定理，看懂了其最严密的推导过程，但却始终没能直观地去理解它。虽然严密的推导是必要的，直观理解往往是不准确的，但如果能悟出一个让定理一瞬间变得很显然的解释，这不但是一件很酷的事，而且对定理更透彻的理解和更熟练的运用也很有帮助。</p></blockquote>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/01/generalization-to-buffons-needle/" title="蒲丰投针问题的推广">蒲丰投针问题的推广</a> (0)</li><li><a href="http://cos.name/2009/09/introduction-and-application-of-gert/" title="用GERT方法求解两个抛硬币问题">用GERT方法求解两个抛硬币问题</a> (11)</li><li><a href="http://cos.name/2008/11/probability-theory-origin-development-application/" title="概率论的起源、发展、应用">概率论的起源、发展、应用</a> (5)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >djstat</a> : <a class="comment_content" href="http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comment-1055" title="View the entire comment by djstat" >直觉的启发太重要。引用你的文章了呵，http://www.jrtj.org/showtopic-13...</a></li>
<li><a class="commentor" href="http://www.public.asu.edu/~shuang31/" >huang shuai</a> : <a class="comment_content" href="http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comment-996" title="View the entire comment by huang shuai" >他估计是要写科幻小说一类的</a></li>
<li><a class="commentor" href="http://taiyun.cos.name/" >魏太云</a> : <a class="comment_content" href="http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comment-972" title="View the entire comment by 魏太云" >matrix67的文章的确很好很新很有趣，惭愧中……</a></li>
<li><a class="commentor" href="http://taiyun.cos.name/" >魏太云</a> : <a class="comment_content" href="http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comment-970" title="View the entire comment by 魏太云" >直觉、灵感真的很重要，我们看见的书上的东西那么完美，但是当时它们都是残缺的，都是数学家的一个灵感什么...</a></li>
<li><a class="commentor" href="http://blog.sina.com.cn/annihiland" >左辰</a> : <a class="comment_content" href="http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/#comment-968" title="View the entire comment by 左辰" >的确很受启发。实际研究时候的灵感都来源于直觉，而technial proof只是一种辅助。</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/11/a-brief-talk-on-buffon-throwing-needle-problems/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>R中的极大似然估计</title>
		<link>http://cos.name/2009/07/maximum-likelihood-estimation-in-r/</link>
		<comments>http://cos.name/2009/07/maximum-likelihood-estimation-in-r/#comments</comments>
		<pubDate>Sun, 19 Jul 2009 00:36:31 +0000</pubDate>
		<dc:creator>胡荣兴</dc:creator>
				<category><![CDATA[概率论与数理统计]]></category>
		<category><![CDATA[统计计算]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[R语言]]></category>
		<category><![CDATA[似然函数]]></category>
		<category><![CDATA[数值优化]]></category>
		<category><![CDATA[极大似然估计]]></category>

		<guid isPermaLink="false">http://cos.name/2009/07/r%e4%b8%ad%e7%9a%84%e6%9e%81%e5%a4%a7%e4%bc%bc%e7%84%b6%e4%bc%b0%e8%ae%a1-2/</guid>
		<description><![CDATA[介结了在R中如何实现极大似然估计的一种实现方法。当然其在R中还有其它的实现方法。]]></description>
			<content:encoded><![CDATA[<p>【注：本文的PDF格式版本可以从<a title="http://cos.name/wp-content/uploads/2009/07/ML.pdf" href="http://cos.name/wp-content/uploads/2009/07/ML.pdf" rel='nofollow'>这里</a>下载。】</p>
<p>什么？你问我什么是<strong>极大似然估计</strong>么？这个嘛，看看你手边的概率或统计教材吧。没有么？那就到<a href="http://zh.wikipedia.org/w/index.php?title=%E6%9C%80%E5%A4%A7%E4%BC%BC%E7%84%B6%E4%BC%B0%E8%AE%A1&amp;variant=zh-cn" rel='nofollow'>维基百科</a>上去看看。</p>
<h1>1. 数据与模型</h1>
<p>我们要使用的数据来自于“MASS”包中的geyser数据。先把数据调出来，看看它长什么样子。</p>
<pre>&gt; geyser
    waiting  duration
1        80 4.0166667
2        71 2.1500000
3        57 4.0000000
4        80 4.0000000
5        75 4.0000000
......</pre>
<p>该数据采集自美国黄石公园内的一个名叫Old Faithful 的喷泉。“waiting”就是喷泉两次喷发的间隔时间，“duration”当然就是指每次喷发的持续时间。在这里，我们只用到“waiting”数据，为了简单一点，可以使用attach()函数。</p>
<pre>&gt; attach(geyser)</pre>
<p><span id="more-1406"></span></p>
<h1>2. 模型</h1>
<p>绘制出数据的频率分布直方图：</p>
<pre>&gt; hist(waiting)</pre>
<p><a href="http://cos.name/wp-content/uploads/2009/08/ml_hist.png" rel='nofollow'><img class="aligncenter size-full wp-image-1413" title="ml_hist" src="http://cos.name/wp-content/uploads/2009/08/ml_hist.png" alt="ml_hist" width="480" height="480" /></a><br />
从图中可以看出，其分布是两个正态分布的混合。可以用如下的分布函数来描述该数据</p>
<div style="text-align: center;"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize f%28x%29%3DpN%28x_i%3B%5Cmu_1%2C%5Csigma_1%29%2B%281-p%29N%28x_i%3B%5Cmu_2%2C%5Csigma_2%29" title="f(x)=pN(x_i;\mu_1,\sigma_1)+(1-p)N(x_i;\mu_2,\sigma_2)" alt="f(x)=pN(x_i;\mu_1,\sigma_1)+(1-p)N(x_i;\mu_2,\sigma_2)" align="absmiddle" /></div>
<p>该函数中有5个参数<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize p" title="p" alt="p" align="absmiddle" />、<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cmu_1" title="\mu_1" alt="\mu_1" align="absmiddle" />、<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Csigma_1" title="\sigma_1" alt="\sigma_1" align="absmiddle" />、<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cmu_2" title="\mu_2" alt="\mu_2" align="absmiddle" />、<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Csigma_2" title="\sigma_2" alt="\sigma_2" align="absmiddle" />需要确定。上述分布函数的对数极大似然函数为：</p>
<div style="text-align: center;"><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize l%3D%5Csum_%7Bi%3D1%7D%5En%5Clog%20%5C%7BpN%28x_i%3B%5Cmu_1%2C%5Csigma_1%29%2B%281-p%29N%28x_i%3B%5Cmu_2%2C%5Csigma_2%29%5C%7D" title="l=\sum_{i=1}^n\log \{pN(x_i;\mu_1,\sigma_1)+(1-p)N(x_i;\mu_2,\sigma_2)\}" alt="l=\sum_{i=1}^n\log \{pN(x_i;\mu_1,\sigma_1)+(1-p)N(x_i;\mu_2,\sigma_2)\}" align="absmiddle" /></div>
<h1>3. 估计</h1>
<h2>3.1. 在R中定义对数似然函数：</h2>
<pre>&gt; #定义log-likelihood函数
&gt; LL&lt;-function(params,data)
+ {#参数"params"是一个向量，依次包含了五个参数：p,mu1,sigma1,
+ #mu2,sigma2.
+ #参数"data"，是观测数据。
+ t1&lt;-dnorm(data,params[2],params[3])
+ t2&lt;-dnorm(data,params[4],params[5])
+ #这里的dnorm()函数是用来生成正态密度函数的。
+ f&lt;-params[1]*t1+(1-params[1])*t2
+ #混合密度函数
+ ll&lt;-sum(log(f))
+ #log-likelihood函数
+ return(-ll)
+ #nlminb()函数是最小化一个函数的值，但我们是要最大化log-
+ #likeilhood函数，所以需要在“ll”前加个“-”号。
+ }</pre>
<h2>3.2. 参数估计</h2>
<pre>&gt; #用hist函数找出初始值
&gt; hist(waiting,freq=F)
&gt; lines(density(waiting))
&gt; #拟合函数####optim####
&gt; geyser.res&lt;-nlminb(c(0.5,50,10,80,10),LL,data=waiting,
+ lower=c(0.0001,-Inf,0.0001,-Inf,-Inf,0.0001),
+ upper=c(0.9999,Inf,Inf,Inf,Inf))
&gt; #初始值为p=0.5,mu1=50,sigma1=10,mu2=80,sigma2=10
&gt; #LL是被最小化的函数。
&gt; #data是拟合用的数据
&gt; #lower和upper分别指定参数的上界和下界。</pre>
<h2>3.3. 估计结果</h2>
<pre>&gt; #查看拟合的参数
&gt; geyser.res$par
[1] 0.3075937 54.2026518 4.9520026 80.3603085 7.5076330
&gt; #拟合的效果
&gt; X&lt;-seq(40,120,length=100)
&gt; #读出估计的参数
&gt; p&lt;-geyser.res$par[1]
&gt; mu1&lt;-geyser.res$par[2]
&gt; sig1&lt;-geyser.res$par[3]
&gt; mu2&lt;-geyser.res$par[4]
&gt; sig2&lt;-geyser.res$par[5]
&gt; #将估计的参数函数代入原密度函数。
&gt; f&lt;-p*dnorm(X,mu1,sig1)+(1-p)*dnorm(X,mu2,sig2)
&gt; #作出数据的直方图
&gt; hist(waiting,probability=T,col=0,ylab="Density",
+ ylim=c(0,0.04),xlab="Eruption waiting times")
&gt; #画出拟合的曲线
&gt; lines(X,f)</pre>
<p><a href="http://cos.name/wp-content/uploads/2009/07/clip_image004.jpg" rel='nofollow'><img class="aligncenter size-full wp-image-1404" title="clip_image004.jpg" src="http://cos.name/wp-content/uploads/2009/07/clip_image004.jpg" alt="clip_image004.jpg" width="481" height="480" /></a></p>
<pre>&gt; detach()</pre>
<h1>小结</h1>
<p>从上面的例子可以看出，在R中作极大似然估计，主要就是定义似然后函数，然后再用nlminb函数对参数进行估计。</p>
<h2>参考文献：</h2>
<p>l Brian S. Everitt(2002). <em>A Handbook of Statistical Analyses Using S-Plus</em>(Second Edition). CRC Press LLC</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/12/improve-r-computation-efficiency/" title="也谈提高R语言的运算效率">也谈提高R语言的运算效率</a> (15)</li><li><a href="http://cos.name/2009/03/scatterplot-matrix-visualization/" title="不同版本的散点图矩阵">不同版本的散点图矩阵</a> (17)</li><li><a href="http://cos.name/2009/03/correlation-matrix-visualization/" title="相关矩阵的可视化及其新方法探究">相关矩阵的可视化及其新方法探究</a> (41)</li><li><a href="http://cos.name/2009/03/parallel-coordinates-and-andrews-curve/" title="调和曲线图和轮廓图的比较">调和曲线图和轮廓图的比较</a> (12)</li><li><a href="http://cos.name/2009/01/r-and-sas-new-york-times/" title="R与SAS之争：一个导读">R与SAS之争：一个导读</a> (28)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >尹康</a> : <a class="comment_content" href="http://cos.name/2009/07/maximum-likelihood-estimation-in-r/#comment-854" title="View the entire comment by 尹康" >初始值的设定有什么心得没?如何保证求出来的结果是全局最优？</a></li>
<li><a class="commentor" href="" >栾生</a> : <a class="comment_content" href="http://cos.name/2009/07/maximum-likelihood-estimation-in-r/#comment-812" title="View the entire comment by 栾生" >正是我需要的。对于理解REML太重要了。建议楼主继续系列文章。</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/07/maximum-likelihood-estimation-in-r/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>统计学博文导读：火箭队比赛与分类树、神经网络与降维</title>
		<link>http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/</link>
		<comments>http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 10:02:12 +0000</pubDate>
		<dc:creator>谢益辉</dc:creator>
				<category><![CDATA[数据挖掘与机器学习]]></category>
		<category><![CDATA[统计计算]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[网站导读]]></category>
		<category><![CDATA[分类树]]></category>
		<category><![CDATA[导读]]></category>
		<category><![CDATA[推荐]]></category>
		<category><![CDATA[神经网络]]></category>
		<category><![CDATA[统计学博客]]></category>

		<guid isPermaLink="false">http://cos.name/?p=809</guid>
		<description><![CDATA[即日起，统计之都网站成立“统计学博文导读”栏目，归属于“网站导读”栏目。我们号召广大读者和作者将喜爱的统计学博客文章推荐给我们，以方便更多读者在这个信息爆炸的时代能够快速阅读到优秀的文章；本文是统计之都“统计学博文导读”第一篇，权当示范本栏目的作用。这次我们重点推荐两篇博文，分别来自于刘思喆和左辰，向大家展示统计学理论的生活和思维魅力。]]></description>
			<content:encoded><![CDATA[<p>即日起，统计之都网站成立“统计学博文导读”栏目，归属于“网站导读”栏目。我们号召广大读者和作者将喜爱的统计学博客文章推荐给我们，以方便更多读者在这个信息爆炸的时代能够快速阅读到优秀的文章；本文是统计之都“统计学博文导读”第一篇，权当示范本栏目的作用。这次我们重点推荐两篇博文，分别来自于刘思喆和左辰，向大家展示统计学理论的生活和思维魅力：</p>
<h2>一、火箭队比赛与分类树</h2>
<p> 2009年3月5日，刘思喆发表了“<a title="http://sunbjt.spaces.live.com/blog/cns!C7F9ED721213E4F5!514.entry" href="http://sunbjt.spaces.live.com/blog/cns!C7F9ED721213E4F5!514.entry" target="_blank" rel='nofollow'>从数据看2008-2009赛季的火箭队</a>”一文，文章用分类树（Classification Tree）分析了火箭队2008-2009年的比赛数据，从数据的角度指出了各种比赛指标对结果胜负的影响关系。文章附有两幅分类树图，大力推荐热爱篮球运动并熟悉分类与回归树模型的同仁阅读（尤其是姚明粉丝）。</p>
<p>我本人是篮球白痴，对于各种术语都不懂，因此不多啰嗦，博主能将统计方法灵活应用到身边的数据，对此我深感佩服。</p>
<h2>二、神经网络与降维思想</h2>
<p>2009年3月12日，左辰发表了“<a title="http://blog.sina.com.cn/s/blog_49dbafab0100cla3.html" href="http://blog.sina.com.cn/s/blog_49dbafab0100cla3.html" target="_blank" rel='nofollow'>神經網絡和非線性降維</a>”一文，讲述了神经网络处理多变量数据时的降维思想，从降维的角度说明了隐藏层的作用。顺便提一句，我对左辰的数学修养非常佩服，感兴趣的读者不妨阅读他更多的博文，如“分析的那些人和事”系列（<a href="http://blog.sina.com.cn/s/blog_49dbafab0100bu08.html" target="_blank" rel='nofollow'>一</a>、<a href="http://blog.sina.com.cn/s/blog_49dbafab0100bycz.html" target="_blank" rel='nofollow'>二</a>、<a href="http://blog.sina.com.cn/s/blog_49dbafab0100c6a9.html" target="_blank" rel='nofollow'>三</a>）等。</p>
<h2>三、其它博文</h2>
<p>这里再列举一些我日常阅读的博客以及文章举例：</p>
<ul>
<li><a href="http://ggorjan.blogspot.com/" target="_blank" rel='nofollow'>Gregor Gorjanc</a>的博客：他是一位斯洛文尼亚的研究者，兴趣在于动物繁殖、遗传学、统计学以及R语言。博文举例：<a title="http://ggorjan.blogspot.com/2008/09/excel-2007-for-statistics.html" href="http://ggorjan.blogspot.com/2008/09/excel-2007-for-statistics.html" target="_blank" rel='nofollow'>Excel 2007 for statistics?</a>；推荐原因：Excel在做统计计算和数据处理的时候应该非常小心，这一点往往被众人忽视。</li>
<li>本站作者胡江堂的英文博客“<a href="http://jiangtanghu.blogspot.com/" target="_blank" rel='nofollow'>Incorporate Things of Diverse Natures</a>”：介绍数据挖掘、商务智能、统计学、SAS等内容，目前似乎是资源型博客，你可以找到大量的超级链接指导你去阅读行业发展或免费资源的页面，如<a href="http://jiangtanghu.blogspot.com/2008/12/learn-time-series-analysis-free.html" target="_blank" rel='nofollow'>Learn Time Series Analysis: Free Materials for SAS Users</a>。</li>
<li><a href="http://bojan.3e.pl/weblog/index.php" target="_blank" rel='nofollow'>Michal Bojanowski</a>的博客：这小子目前似乎在荷兰，他的兴趣在于R语言和社会网络分析，有时候会记录一些使用R的小技巧，如<a href="http://bojan.3e.pl/weblog/pivot/entry.php?id=27" target="_blank" rel='nofollow'>R&#8217;s working directory</a>。</li>
<li><a href="http://onertipaday.blogspot.com/" target="_blank" rel='nofollow'>One R Tip A Day</a>：看标题就知道，关于R的小小技巧，闲来无事可以看看，一个意大利大哥写的；如有时候你想将图形的标题文字用几种不同的颜色标记，那么可以读一读<a href="http://onertipaday.blogspot.com/2009/01/interesting-tip-about-multicolor-title.html" rel='nofollow'>Interesting tip about multicolor title of a plot</a>。</li>
<li><a href="http://lixiaoxu.lxxm.com/" target="_blank" rel='nofollow'>李晓煦</a>老师的博客：非常专业，为数不多的会用LaTeX写上数学公式的博客，李老师对统计理论细节研究很认真，很有国外统计研究者的风范；博文如<a title="Permalink to Why practitioners discretize their continuous data" href="http://lixiaoxu.lxxm.com/why-practitioners-discretize-their-continous-data/" rel='nofollow'>Why practitioners discretize their continuous data</a>讲述了为什么大家喜欢将连续型数据离散化的原因之一。</li>
</ul>
<p>各位读者若有好的建议和意见请Email反馈到blog[at]cos.name，欢迎推荐好文章大家一起分享，来信请注明推荐原因（如读后感等）。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/06/stat-blog-guide-ahmadinejad-votes/" title="统计学博文导读：内贾德大选作弊？流星撞飞机的概率？买双色球？">统计学博文导读：内贾德大选作弊？流星撞飞机的概率？买双色球？</a> (6)</li><li><a href="http://cos.name/2009/03/cos-navigation-9/" title="统计之都《本周导读》第九辑">统计之都《本周导读》第九辑</a> (0)</li><li><a href="http://cos.name/2009/02/cos-navigation-8/" title="统计之都《本周导读》第八辑">统计之都《本周导读》第八辑</a> (0)</li><li><a href="http://cos.name/2009/01/cos-navigation-7/" title="统计之都《本周导读》第七辑">统计之都《本周导读》第七辑</a> (0)</li><li><a href="http://cos.name/2009/01/cos-navigation-6/" title="统计之都《本周导读》第六辑">统计之都《本周导读》第六辑</a> (0)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >alexchen</a> : <a class="comment_content" href="http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/#comment-703" title="View the entire comment by alexchen" >多谢多谢，如果说网页设计的话，个人认为黑色过于庄严了。。。仅供参考~</a></li>
<li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/#comment-383" title="View the entire comment by 谢益辉" >谢谢，错别字已经更正，小字号也调大了。COS的logo我还没想好做成什么样，以前那个我个人其实不太满...</a></li>
<li><a class="commentor" href="" >fan</a> : <a class="comment_content" href="http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/#comment-378" title="View the entire comment by fan" >谢谢谢老大无私的分享！BTW，恕我提出几点个人意见，仅供参考：“作者信息”里“前言”应改为“前沿”，...</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/03/stat-blog-guide-rocket-cart-nnet/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
