<?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/software/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>北京数据管理与生物统计论坛（BBF）第三次聚会见闻录</title>
		<link>http://cos.name/2010/09/3rd-bbf/</link>
		<comments>http://cos.name/2010/09/3rd-bbf/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 15:39:39 +0000</pubDate>
		<dc:creator>胡江堂</dc:creator>
				<category><![CDATA[生物与医学统计]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[行业观察]]></category>
		<category><![CDATA[高校课堂]]></category>
		<category><![CDATA[BBF]]></category>
		<category><![CDATA[SAS]]></category>
		<category><![CDATA[SAS程序员]]></category>
		<category><![CDATA[生物统计]]></category>

		<guid isPermaLink="false">http://cos.name/2010/09/3nd-bbf/</guid>
		<description><![CDATA[9月4号下午，周六，去北大医学部参加了北京数据管理与生物统计论坛（Beijing Biometrics Forum， BBF）的第三次聚会，这次活动由SAS China和北京大学临床研究所赞助。这里写些会议见闻和一些零散的感想，不算是会议的正式“纪要”。东西贴这，大致想给“统计之都”(COS)的朋友交流下北京SAS技术社区的氛围、工作市场情况以及一些相关技术评论等等。 1. 话题 西安杨森的薛富波博士做的开幕致辞，他也是BBF的召集人。SAS China的市场部总监罗威先生代表SAS公司做了欢迎致辞。下面是六位主题发言人的演讲简介以及我的一些杂感。 1.1 SAS程序编写规范(Good SAS Programming Development Practices) 演讲者是赛诺菲-安万特的李友先生，也是本次活动的主持人。除了行业监管规范（如21 CFR Part 11），李还提到SAS的代码规范，如花盒子注释（程序头）、代码结构、缩进、命名规则、可重用性和效率等等议题。这些问题，各个公司各个程序员可能都有不同的风格不同的偏好，但李给的这个较为全面的梳理，还是非常有启发意义的。 对传统程序员（C/C++、Java、Perl、……）来说，代码风格、质量以及重构都是很好理解的事情，但这些却是大量SAS程序员需要补的课。SAS程序员背景多样，主要以统计、数学、生物、医学为主，大多缺少这方面的训练，认为写出的代码能够完成工作就万事大吉。这里除了对SAS运行机制的理解层次不一样，还有一个代码品味的问题。如果把整页整页的代码看成一篇散文，从观感上，相信每个人都能判断出，哪些代码至少“看上去”像是非常好代码。 李提到他幻灯片里介绍SAS软件的部分，参考了“统计之都”的博文——原来也有同行在看这里的文字。国内SAS程序员散布四处，有些在COS潜水，有些在mysas.net灌水，有些喜欢类似BBF的线下交流，浮出水面，可能大伙看着都脸熟。 关于代码规范。还有一个比较少见但却是非常有意思的可能，那就是，“非不能也，实不为也。”怎么说？咱不是水平不行，也不是品味极差，但为了保住饭碗，俺就是要把代码写得极怪，以使后人无法接手维护，从而保证了自己的不可替代性。这种人被称作Job Security Specialist。有点可笑了，呆伯特有一句说得好，笑笑： Don&#8217;t be irreplaceable, if you can&#8217;t be replaced, you can&#8217;t be promoted. 1.2 PROC SQL在临床试验中的应用（PROC SQL Applied in Biometrics） 演讲者是RPS的吴崇胜先生，介绍的是PROC SQL在临床数据分析中的应用，包括数据校验、数据汇总等，强调了PROC SQL跟data steps（数据步）相比对列进行处理的优势。 一个SAS程序员的工具箱分为两类，一是传统SAS的data steps，二就是SQL。——说到这里，我要先提一下“SAS程序员”和“SAS使用者”的区别： SAS程序员在文本编辑器里写代码，里面主要是data steps和SQL，穿插以Macro（宏）和其他procs（程序步）等等，总之，一个“SAS程序员”几乎就是一个“SAS/BASE程序员”。 而“SAS使用者”，他们或者单纯使用SAS的客户端工具，如Enterprise Guider、Analyst、SAS Add-In for [...]]]></description>
			<content:encoded><![CDATA[<p>9月4号下午，周六，去北大医学部参加了北京数据管理与生物统计论坛（Beijing Biometrics Forum， BBF）的第三次聚会，这次活动由<a href="http://sas.com.cn/" rel='nofollow'>SAS China</a>和<a href="http://pucri.bjmu.edu.cn/" rel='nofollow'>北京大学临床研究所</a>赞助。这里写些会议见闻和一些零散的感想，不算是会议的正式“<a href="http://cos.name/2010/06/3rd-china-r-beijing-summary/" rel='nofollow'>纪要</a>”。东西贴这，大致想给“<a href="http://cos.name/" rel='nofollow' rel='nofollow'>统计之都</a>”(COS)的朋友交流下北京SAS技术社区的氛围、工作市场情况以及一些相关技术评论等等。</p>
<p><strong>1. 话题</strong></p>
<p>西安杨森的薛富波博士做的开幕致辞，他也是BBF的召集人。SAS China的市场部总监罗威先生代表SAS公司做了欢迎致辞。下面是六位主题发言人的演讲简介以及我的一些杂感。</p>
<p><span id="more-2489"></span></p>
<p><strong><span style="color: #ff0000;">1.1</span> SAS程序编写规范(Good SAS Programming Development Practices)</strong></p>
<p>演讲者是赛诺菲-安万特的李友先生，也是本次活动的主持人。除了行业监管规范（如<em><a href="http://en.wikipedia.org/wiki/Title_21_CFR_Part_11" rel='nofollow'>21 CFR Part 11</a></em>），李还提到SAS的代码规范，如花盒子注释（程序头）、代码结构、缩进、命名规则、可重用性和效率等等议题。这些问题，各个公司各个程序员可能都有不同的风格不同的偏好，但李给的这个较为全面的梳理，还是非常有启发意义的。</p>
<p>对传统程序员（C/C++、Java、Perl、……）来说，代码风格、质量以及重构都是很好理解的事情，但这些却是大量SAS程序员需要补的课。SAS程序员背景多样，主要以统计、数学、生物、医学为主，大多缺少这方面的训练，认为写出的代码能够完成工作就万事大吉。这里除了对SAS运行机制的理解层次不一样，还有一个代码品味的问题。如果把整页整页的代码看成一篇散文，从观感上，相信每个人都能判断出，哪些代码至少“看上去”像是非常好代码。</p>
<p>李提到他幻灯片里介绍SAS软件的部分，参考了<a href="http://cos.name/2010/04/think-sas-1/" rel='nofollow'>“统计之都”的博文</a>——原来也有同行在看这里的文字。国内SAS程序员散布四处，有些在<a href="http://cos.name/" rel='nofollow'>COS</a>潜水，有些在<a href="http://mysas.net/forum/index.php" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>mysas.net</a>灌水，有些喜欢类似BBF的线下交流，浮出水面，可能大伙看着都脸熟。</p>
<p>关于代码规范。还有一个比较少见但却是非常有意思的可能，那就是，“非不能也，实不为也。”怎么说？咱不是水平不行，也不是品味极差，但为了保住饭碗，俺就是要把代码写得极怪，以使后人无法接手维护，从而保证了自己的不可替代性。这种人被称作Job Security Specialist。有点可笑了，呆伯特有一句说得好，笑笑：</p>
<blockquote><p>Don&#8217;t be irreplaceable, if you can&#8217;t be replaced, you can&#8217;t be promoted.</p></blockquote>
<p><strong><span style="color: #ff0000;">1.2</span> PROC SQL在临床试验中的应用（PROC SQL Applied in Biometrics）</strong></p>
<p>演讲者是RPS的吴崇胜先生，介绍的是PROC SQL在临床数据分析中的应用，包括数据校验、数据汇总等，强调了PROC SQL跟data steps（数据步）相比对列进行处理的优势。</p>
<p>一个SAS程序员的工具箱分为两类，一是传统SAS的data steps，二就是SQL。——说到这里，我要先提一下“SAS程序员”和“SAS使用者”的区别：</p>
<ul>
<li>SAS程序员在文本编辑器里写代码，里面主要是data steps和SQL，穿插以Macro（宏）和其他procs（程序步）等等，总之，一个“SAS程序员”几乎就是一个“SAS/BASE程序员”。</li>
<li>而“SAS使用者”，他们或者单纯使用SAS的客户端工具，如Enterprise Guider、Analyst、SAS Add-In for Microsoft Office，或者也写主要以procs为主的代码（显然，有的SAS使用者会成长为SAS程序员，有的SAS程序员也会转化成SAS使用者）。</li>
</ul>
<p>SAS的PROC SQL是标准SQL（<a href="http://en.wikipedia.org/wiki/SQL-92" rel='nofollow'>SQL-92</a>）的一个实现，你可以把在其他任何场合学到的大部分SQL知识不加修改地移植到PROC SQL里面来。这也能提供一部分的解释，为什么以前是统计系学生专场的SAS程序员群体，有越来越多的IT背景的人员加入。</p>
<p>data steps跟SQL是左青龙右白虎，混合使用，扬长避短，才能相得益彰。SAS data steps脱胎于PL/1，是一门过程式的语言，而SQL呢？它的全称是Structured Query Language（结构式查询语言），但其实，SQL既不是结构式的，也不仅仅是用来查询的，最后，从图灵完全的角度，它也不能算作一门“语言”（比如，标准SQL就做不了循环）。</p>
<p><strong><span style="color: #ff0000;">1.3</span> PROC FCMP介绍</strong></p>
<p>演讲者是我的前同事，SAS R&amp;D的覃龙先生。有了PROC FCMP，你就可以像其他语言一样，定义自己的函数了，而不是只用SAS Macro定义一个“类似函数的”宏。覃的报告分为两部分，一是用PROC FCMP的数据功能(array)，实现类似SAS/IML的矩阵运算，二就是用PROC FCMP自定义函数了。</p>
<p>PROC FCMP是SAS 9.2版本的一个亮点，其实在9.1.3也有它一个实验版本，可以拿来练练手。又，覃提到SAS Macro不能做递归，其实它是可以的，也不是很麻烦（当然不如在PROC FCMP里写着顺畅）。</p>
<p><strong><span style="color: #ff0000;">1.4</span> 让SAS作图变得更容易：%GraphLineplt (%GraphLineplt: Made Graph Easy)</strong></p>
<p>演讲者是赛诺菲-安万特的李华丹先生。%GraphLineplt是李开发的一套多功能的作图程序，整个发言就是讲解这套宏的构架与使用。我对作图没有特别的研究，对着文档照葫芦画瓢而已。主要印象，一是作图元素的分解，二是用data steps辅助（annotate功能）。听这个演讲，至少知道，以后有问题，可以直接找谁请教了。</p>
<p><strong><span style="color: #ff0000;">1.5</span> 一些SAS小技巧(Tricks Make Life Easy)</strong></p>
<p>演讲者是诺和诺德的于文博先生，去年在CDISC Interchange 2009的培训会场见过。于介绍了SAS的两个实用小技巧，一是Add Abbreviation，二是Record Keyboard Macros。当然，他发言的精华不在这里。展示完这些小技巧后，于说道：</p>
<blockquote><p>all tricks are in the dust. 所有技巧都是过眼云烟。</p></blockquote>
<p>接着于就展示了质量控制专家戴明著名的“戴明环”(<a href="http://en.wikipedia.org/wiki/PDCA" rel='nofollow'>Deming Cycle</a>)，一个计划、执行、检查、处理的闭环。虽然衔接得有些无厘头，于还是有效地把会场的气氛大大提升了一把。戴明环对项目管理很有启发意义。</p>
<p><strong><span style="color: #ff0000;">1.6</span> 医药行业SAS程序员职业发展探讨(Career path of SAS programmer in pharmaceutical industry)</strong></p>
<p>演讲者是Covance的邓亚中先生。邓这次演讲带了很多干货：</p>
<ul>
<li>SAS程序员在医药行业的分工</li>
<li>SAS程序员的职业转向（技术专家、咨询顾问、管理、培训等等）</li>
<li>国内药厂和CRO统计师和SAS程序员的数量和分布（有图有真相，整整两页胶片，大伙看着都是非常感兴趣）</li>
</ul>
<p>关于SAS程序员，现在国际上的大药厂以及CRO纷纷在中国设点，邓说，就今年国内还有100个缺口（<em>邓在发言中也顺便给他们公司招聘做做话题广告</em>）：这100个人，往哪里找啊？国内高校，SAS教育的状况不容乐观。李友后来插一句，就仰仗各位帮扶带了。</p>
<p><strong>2. 人物</strong></p>
<p><strong><span style="color: #ff0000;">2.1</span> 薛富波(Bruce Xue)</strong></p>
<p>第一感觉就是，比我印象中年轻多了（<em>Bruce，在我印象中，你也不“老”，只是……</em>）。我06年开始学习SAS（版本9.13），跟那时很多初学者一样，手头也都摆了Bruce的《SAS宏语言基础》以及他与上海张文彤等人合著的《<a href="http://www.china-pub.com/20959" rel='nofollow'>SAS 8.2统计应用教程</a> 》（2004）。当时他还在西安，第四军医大。怎么说？印象中Bruce有我老师般的年龄，见面却是我经理的年龄，——俗语一句，闻名不如见面，见面更胜闻名呀。</p>
<p>提到国内SAS教育的先行者，北大统计系的高惠璇老师已经退休，上面提到的张文彤，也离开了复旦，最近在<a href="http://info.taobao.com/detail/data/8f/fb/8ffbb149-e137-416b-a037-75c71519f2b2_1.php" rel='nofollow'>淘宝网的数据门户看到一则消息</a>，说他已经转入上海一家市场研究公司。在北京，如果嫌自学SAS不好玩，可以去高校找找现在还活跃的老师：</p>
<ul>
<li>军事医学科学院的<strong>胡良平</strong>教授，这个秋季学期在中科院研究生院开SAS课；</li>
<li>按照<strong>朱世武</strong>教授的一贯安排，这个秋季学期他也会在清华大学经管学院开两三门SAS与金融计算的课程，本科高年级和研究生两种水平类别；</li>
<li>北大统计系<strong>李东风</strong>教授这个秋季学期会开一门“临床试验SAS高级编程”(<em>SAS Programming in Clinical Trials</em>)的选修课，针对大四毕业生。同时，这个秋季学期，北大统计系还开有一门“临床试验设计与分析”(<em>Clinical trial design and analysis</em>）。个人感觉，这是北大统计系对最近几年国内生物统计市场蓬勃发展的一个反应。真很可贵的尝试。</li>
</ul>
<p>另外，按照人大统计系的某些实用主义传统，这个秋季学期或者明年春季学期，也会开设相应的SAS的课程。大学乃社会公器，认为未注册的人来蹭课会“扰乱教学秩序”只是大学的“教务部观点”，而非大学的“教授观点”。讲讲北大的氛围，假设，80人的教室刚好容纳80位注册学生，然后一共有100人来听课，你就不知道坐在位子上的80位、后排站着的10位、还有前排地板坐着的10位谁是注册生谁是旁听生。老师继续上课，相安无事。然后，教室再挤来20位蹭课的。课堂终于混乱了，教授说：“我们再换一个大点的教室吧。”上次回学校，图书馆迎新生，拉了一个条幅，上书“得天下英才而教之，遍读经典以传承”，居然感动地一塌糊涂。</p>
<p><strong><span style="color: #ff0000;">2.2</span> </strong><a href="http://cos.name/cn/profile/103519" target="_blank" rel='nofollow'><strong>tangyh</strong></a></p>
<p><a href="http://cos.name/cn/profile/103519" target="_blank" rel='nofollow' rel='nofollow'>tangyh</a>是“<a href="http://cos.name/" target="_blank" rel='nofollow' rel='nofollow'>统计之都</a>”(COS)<a href="http://cos.name/cn/forum/14" target="_blank" rel='nofollow'>SAS版</a>的版主，现在中科院读研，数据挖掘方向，刚在赛诺菲巴斯德生物统计部结束暑期实习，是解决问题能力很强的SAS好手，会上也有猎头过来问候。想，等两三年后，如果<a href="http://cos.name/cn/profile/103519" target="_blank" rel='nofollow' rel='nofollow'>tangyh</a>对工业界感兴趣，我要第一个给他打电话。</p>
<p><strong><span style="color: #ff0000;">2.3</span> </strong><a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow'><strong>hopewell</strong></a></p>
<p><a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>是国内最火的SAS中文论坛<a href="http://mysas.net/forum/index.php" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>mysas.net</a>的版主，最近几年在mysas.net上写代码是写得风生水起。之前我们简单沟通过，正好趁着这个聚会混个脸熟。</p>
<p>讲个小插曲。<a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>下午来的时候，手机刚好停电，我就在会场冲着感觉像他的面孔招手。后来<a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>同学通过组织会议的一位朋友找到我，自我介绍说是<a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>，我那朋友看着没反应，我差点叫出来，<a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>这个ID都不认识。唉，不是所有的SAS程序员都上<a href="http://mysas.net/forum/index.php" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>mysas.net</a>的。虽然SAS公司的laosunny在<a href="http://mysas.net/forum/index.php" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>mysas.net</a>发了<a href="http://mysas.net/forum/viewtopic.php?f=8&amp;t=6665" rel='nofollow'>本次活动的预告</a>，但感觉BBF跟<a href="http://mysas.net/forum/index.php" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>mysas.net</a>沟通不多。这次BBF大体上是一个通过工作邮箱召集的活动。</p>
<p>回到<a href="http://mysas.net/forum/memberlist.php?mode=viewprofile&amp;u=16659&amp;sid=156400e66af45ba1ce53c31caefc526d" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>hopewell</a>同学，一起海聊了。瞅个话档，我又厚颜无耻地问他对我公司感不感兴趣。碰到高手，我的第一个反应就是能不能邀请过来做同事，噫。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/04/think-sas-1/" title="Think SAS(一)">Think SAS(一)</a> (92)</li><li><a href="http://cos.name/2009/08/econ-software-sas/" title="我的求学之路：经济学、软件工程、SAS">我的求学之路：经济学、软件工程、SAS</a> (31)</li><li><a href="http://cos.name/2010/05/from-clt-simulation-to-normal-distribution/" title="从中心极限定理的模拟到正态分布">从中心极限定理的模拟到正态分布</a> (35)</li><li><a href="http://cos.name/2009/02/measure-classification-model-performance-lift-gain/" title="分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(3): Lift和Gain">分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(3): Lift和Gain</a> (7)</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://jiangtanghu.com" >胡江堂</a> : <a class="comment_content" href="http://cos.name/2010/09/3rd-bbf/#comment-1624" title="View the entire comment by 胡江堂" >多谢编辑同学帮我修订哈。

to tangyh：你这个想法，国外有两个类似的网站，一是http:...</a></li>
<li><a class="commentor" href="" >hgzhang</a> : <a class="comment_content" href="http://cos.name/2010/09/3rd-bbf/#comment-1621" title="View the entire comment by hgzhang" >PROC FCMP的数据功能,真是好工具！</a></li>
<li><a class="commentor" href="" >阎小妍</a> : <a class="comment_content" href="http://cos.name/2010/09/3rd-bbf/#comment-1620" title="View the entire comment by 阎小妍" >天啊。。。我们的新闻稿还在审~论坛就已经贴出来了。。真迅速啊~~~</a></li>
<li><a class="commentor" href="http://yaohua.cos.name/cn/" >tangyh</a> : <a class="comment_content" href="http://cos.name/2010/09/3rd-bbf/#comment-1619" title="View the entire comment by tangyh" >会上，好像是罗威先生提到自己学习SAS的时候说是遇到问题了找不到可以问的人。
我想学长开始学习sa...</a></li>
<li><a class="commentor" href="http://bjt.name" >刘思喆</a> : <a class="comment_content" href="http://cos.name/2010/09/3rd-bbf/#comment-1618" title="View the entire comment by 刘思喆" >现场挖人，哈哈</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2010/09/3rd-bbf/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Think SAS(一)</title>
		<link>http://cos.name/2010/04/think-sas-1/</link>
		<comments>http://cos.name/2010/04/think-sas-1/#comments</comments>
		<pubDate>Sun, 18 Apr 2010 07:57:09 +0000</pubDate>
		<dc:creator>胡江堂</dc:creator>
				<category><![CDATA[应用领域]]></category>
		<category><![CDATA[数据分析]]></category>
		<category><![CDATA[生物与医学统计]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[行业观察]]></category>
		<category><![CDATA[Fortran]]></category>
		<category><![CDATA[Maple]]></category>
		<category><![CDATA[Mathematica]]></category>
		<category><![CDATA[MatLab]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[S-plus]]></category>
		<category><![CDATA[SAS]]></category>
		<category><![CDATA[SAS程序员]]></category>
		<category><![CDATA[SPSS]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[商务智能]]></category>
		<category><![CDATA[求职]]></category>
		<category><![CDATA[统计]]></category>
		<category><![CDATA[统计之都]]></category>
		<category><![CDATA[统计工具]]></category>

		<guid isPermaLink="false">http://cos.name/2010/04/think-sas/</guid>
		<description><![CDATA[为什么你应该学SAS？本文不想卷入SAS与R，或者与SPSS、S-Plus、Matlab等统计软件孰优孰劣的争论中去，我是说，作为一个有志于投身工业界的统计分析人员，你为什么应该把SAS纳入你的分析工具箱？这会是一篇动员贴，尤其是对广大对数据分析感兴趣的在校生。在默认统计编程语言是R的“统计之都”，我需要拿上面这幅图来吸引眼球：学SAS吧。 R是好东西，不只是在COS，现在全世界的统计系和统计学生当中，R是主导性的学术语言。但不妙的是，国内高校学生中，学SAS的明显少了，医药、金融等行业经常苦于招不到合适的SAS程序员。在统计分析领域，SAS是主导性的工业语言，它与R，不应该是此消彼长的关系。工业界与学院的隔膜，现在我感觉是非常明显。下面讲的就是，关于SAS，我们在学院可能不太关注的事实。 0. SAS是什么？ 这是一个问题，SAS已经不是你所想象的那个样子。作为一家年收入超过20亿美元的、全球最大的独立BI/分析厂商，SAS就是那家由Dr. Jim Goodnight领导的私人公司。作为一个庞大的软件系统，以下只是SAS系统的一个不完整、不系统的介绍： 1.传统SAS（编程驱动） 1-1 基础模块（Base SAS）：包括类似于PL/L的第四代编程语言data steps、SQL、ODS、XML Engine、Macro以及大量的内置函数（支持Perl 正则表达式）和过程步(procedures)等。对一个SAS程序员来说，这个BASE模块几乎就是全部（说学SAS，就是先学这个，这不需要统计背景或者计算机背景）。又，狭义的SAS Base仅指data steps。 1-2 数据存取模块（SAS/ACCESS）：支持大量的PC文件（除文本文件外，还包括Excel、SPSS的.sav、Stata的.dta等等）以及所有主流的关系数据库及ERP系统（Oracle、SAP、SQL Server、DB2、MySQL等等） 1-3 作图模块(SAS/GRAPH)：SAS作图功能强大，只是模样够土。新版SAS 9.2在这块有不少让人兴奋的改进，比如支持ODS、TrueColor、ActiveX、SVG（Scalable Vector Graphics）等，另外还加了一个graph editor，新潮不少。 1-4 统计分析模块(SAS/STAT ) ：包括回归模型、方差分析模型、混合模型、贝叶斯分析、分类数据分析、多元分析（主成分和因子分析等）、判别分析、聚类分析、生存分析、非参数分析等，多是我不熟悉的领域，只管罗列。有个Stat Studio支持R。 1-5 时间序列与计量经济学模块（SAS/ETS ）：同上，X11、X12、ARIMA、PANEL、AUTOREG、……。又，做资产组合等投资分析也是在这个模块。 1-6 矩阵运算模块(SAS/IML) 1-7 运筹学模块(SAS/OR) 1-8 地理信息系统模块(SAS/GIS) …… 以上部分是大部分SAS高校用户能接触到的东西，主要用命令行实现功能。下面则是有GUI的客户端工具，一般都用它们作计算引擎。 2. 客户端工具 2-1 元数据管理(SAS Management Console，SMC):元数据(metadata)就是关于数据的数据。最简单的，一个数据集的变量属性就是metadata。SMC是SAS产品元数据管理的统一中心。 2-2 ETL工具(SAS Data Integration Studio)：ETL就是数据抽取(Extract)、转换(Transform)和加载(Load)。完成企业数据处理的工具还有SAS OLAP Cube Studio、SAS [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://cos.name/wp-content/uploads/2010/04/think_SAS.jpg" rel='nofollow'><img class="alignleft" style="border: 0pt none; margin-left: auto; margin-right: auto;" src="http://cos.name/wp-content/uploads/2010/04/think_SAS.jpg" border="0" alt="think_SAS" width="220" height="200" / rel='nofollow' rel='nofollow'></a> 为什么你应该学SAS？本文不想卷入SAS与R，或者与SPSS、S-Plus、Matlab等统计软件孰优孰劣的争论中去，我是说，<strong>作为一个有志于投身工业界的统计分析人员，你为什么应该把SAS纳入你的分析工具箱</strong>？这会是一篇动员贴，尤其是对广大对数据分析感兴趣的在校生。在默认统计编程语言是R的“<a href="http://cos.name/2008/11/which-statistical-software-should-we-use/" rel='nofollow'>统计之都</a>”，我需要拿上面这幅图来吸引眼球：学SAS吧。</p>
<p>R是好东西，不只是在COS，现在全世界的统计系和统计学生当中，R是主导性的学术语言。但不妙的是，国内高校学生中，学SAS的明显少了，医药、金融等行业经常苦于招不到合适的SAS程序员。在统计分析领域，SAS是主导性的工业语言，它与R，不应该是此消彼长的关系。工业界与学院的隔膜，现在我感觉是非常明显。下面讲的就是，关于SAS，我们在学院可能不太关注的事实。<span id="more-2142"></span></p>
<h2>0. SAS是什么？</h2>
<p>这是一个问题，SAS已经不是你所想象的那个样子。作为一家年收入超过20亿美元的、全球最大的<strong>独立</strong>BI/分析厂商，SAS就是那家由Dr. Jim Goodnight领导的私人公司。作为一个庞大的软件系统，以下只是SAS系统的一个不完整、不系统的介绍：</p>
<blockquote>
<h3>1.传统SAS（编程驱动）</h3>
<p>1-1 基础模块（<span style="color: #ff0000;">Base SAS</span>）：包括类似于PL/L的第四代编程语言data steps、SQL、ODS、XML Engine、Macro以及大量的内置函数（支持Perl 正则表达式）和过程步(procedures)等。对一个SAS程序员来说，这个BASE模块几乎就是全部（说学SAS，就是先学这个，这不需要统计背景或者计算机背景）。又，狭义的SAS Base仅指data steps。</p>
<p>1-2 数据存取模块（<span style="color: #404040;">SAS/ACCESS</span>）：支持大量的PC文件（除文本文件外，还包括Excel、SPSS的.sav、Stata的.dta等等）以及所有主流的关系数据库及ERP系统（Oracle、SAP、SQL Server、DB2、MySQL等等）</p>
<p>1-3 作图模块(<span style="color: #404040;">SAS/GRAPH</span>)：SAS作图功能强大，只是模样够土。新版SAS 9.2在这块有不少让人兴奋的改进，比如支持ODS、TrueColor、ActiveX、SVG（Scalable Vector Graphics）等，另外还加了一个graph editor，新潮不少。</p>
<p>1-4 统计分析模块(<span style="color: #404040;">SAS/STAT</span> ) ：包括回归模型、方差分析模型、混合模型、贝叶斯分析、分类数据分析、多元分析（主成分和因子分析等）、判别分析、聚类分析、生存分析、非参数分析等，多是我不熟悉的领域，只管罗列。有个Stat Studio支持R。</p>
<p>1-5 时间序列与计量经济学模块（<span style="color: #404040;">SAS/ETS</span> ）：同上，X11、X12、ARIMA、PANEL、AUTOREG、……。又，做资产组合等投资分析也是在这个模块。</p>
<p>1-6 矩阵运算模块(SAS/IML) 1-7 运筹学模块(SAS/OR) 1-8 地理信息系统模块(SAS/GIS) …… 以上部分是大部分SAS高校用户能接触到的东西，主要用命令行实现功能。下面则是有GUI的客户端工具，一般都用它们作计算引擎。</p>
<h3>2. 客户端工具</h3>
<p>2-1 元数据管理(SAS Management Console，SMC):元数据(metadata)就是关于数据的数据。最简单的，一个数据集的变量属性就是metadata。SMC是SAS产品元数据管理的统一中心。</p>
<p>2-2 ETL工具(<span style="color: #404040;">SAS Data Integration Studio</span>)：ETL就是数据抽取(Extract)、转换(Transform)和加载(Load)。完成企业数据处理的工具还有SAS OLAP Cube Studio、SAS Information Map Studio等。</p>
<p>2-3 数据挖掘模块(<span style="color: #404040;">SAS Enterprise Miner，EM</span>) ：SAS的重磅产品之一。5以上是Java客户端版本，用户体验增进不少。</p>
<p>2-4 综合分析工具包(SAS Enterprise Guide，EG): 有完善的GUI界面，完成SAS从数据整合、分析到报表的一系列功能。EG与JMP，是SAS公司的两个明星产品。 ……</p>
<h3>3. 其他</h3>
<p>3-1 统计探索软件包<span style="color: #ff0000;">JMP</span>：这是一个独立于Base SAS的软件，由SAS公司的二把手John Sall主管，界面很炫，功能很强，让业务人员爱不释手那种。JMP9支持R。 ……</p></blockquote>
<p>以及，由以上SAS产品整合打包、再加上业务规则支持形成的各种SAS行业解决方案，广泛运用于金融、通信、能源、政府、医药、保险、制造、零售等各个行业。 SAS不仅仅是一款统计软件，它的官方定位是“商务分析和商务智能软件”(Business Analytics and Business Intelligence Software, BA &amp; BI)。现在我们的重点放回SAS 1.1 即<span style="color: #ff0000;">Base SAS</span>上来。</p>
<h2>1. SAS是最流行的数据分析类语言</h2>
<p>我们看一个编程语言4月份的排名，来自<a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>TIOBE</a>。<a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>TIOBE</a>编程语言排名是各种程序语言流行程度的指标，每月更新。它参考全球范围内的技术工程师、培训师以及第三方厂商的意见，通过google、MSN、Yahoo!等常用的搜索引擎搜索结果来计算每种编程语言的流行指数。这个排行榜是程序员查看自己掌握的编程技能是否过时的权威参考之一。具体的评分标准，可以参阅其<a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/tpci_definition.htm" rel='nofollow'>官分评分文档</a>。现在最新的排行榜是（前20名，2010年4月）：</p>
<p><a href="http://cos.name/wp-content/uploads/2010/04/rank_2010041.png" rel='nofollow'><img class="aligncenter" style="border: 0pt none; width: 451px; margin-left: auto; margin-right: auto;" src="http://cos.name/wp-content/uploads/2010/04/rank_2010041.png" border="0" alt="rank_201004" width="451" height="587" / rel='nofollow' rel='nofollow'></a></p>
<p>这个<a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>TIOBE</a>排名，有它自身的局限。比如，Google新推出的Go，一时广受追捧，4月的排名噌就上去了，但这并不能代表它的实际流行程度。但长期看来，模式还是很明显，比如，通用型的编程语言C/C++、Java、Perl、Python等一直占据这个榜单的榜首，而SAS，则一直是数据分析类语言的龙头，与Oracle数据库内置的PL/SQL语言不分上下。在2010年4月这份榜单中，我们可以把常见的统计分析类语言<span style="font-size: x-small;">（关于“统计分析类语言”，这里表述不够精确，比如Matlab，可以作为统计分析工具用，但更多用在科学计算方面。得其大意了。）</span>单独摘出来做一份表单（Maple、Mathematica、R和SPSS由于在榜单上差异不大，故按字母顺序排序）：</p>
<div>
<table border="0" cellspacing="0" cellpadding="2" width="345" align="center">
<tbody>
<tr>
<td width="48" valign="top"></td>
<td width="124" valign="top">统计分析语言</td>
<td width="171" valign="top"><a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" rel='nofollow' rel='nofollow' rel='nofollow' rel='nofollow'>TIOBE</a>排名2010年4月</td>
</tr>
<tr>
<td width="48" valign="top">1</td>
<td width="124" valign="top">SAS</td>
<td width="171" valign="top">13</td>
</tr>
<tr>
<td width="48" valign="top">2</td>
<td width="124" valign="top">Matlab</td>
<td width="171" valign="top">18</td>
</tr>
<tr>
<td width="48" valign="top">3</td>
<td width="124" valign="top">Fortran</td>
<td width="171" valign="top">34</td>
</tr>
<tr>
<td width="48" valign="top">4</td>
<td width="124" valign="top">Maple</td>
<td width="171" valign="top">#51 to #100</td>
</tr>
<tr>
<td width="48" valign="top">5</td>
<td width="124" valign="top">Mathematica</td>
<td width="171" valign="top">#51 to #100</td>
</tr>
<tr>
<td width="48" valign="top">6</td>
<td width="124" valign="top">R</td>
<td width="171" valign="top">#51 to #100</td>
</tr>
<tr>
<td width="48" valign="top">7</td>
<td width="124" valign="top">SPSS</td>
<td width="171" valign="top">#51 to #100</td>
</tr>
</tbody>
</table>
</div>
<p><strong>SAS是工业界最流行的统计分析语言。</strong>以前，号称有工业用途的三个统计软件是SAS、S-plus和SPSS，它们都是二十世纪七十年代问世的。S-plus与R同源，根正苗红，前身是上世纪七十年代末诞生于AT&amp;T的贝尔实验室(Bell Labs)的S语言，八十年代末由<a href="http://www.jiangtanghu.com/cn/2009/01/15/%E5%BF%83%E9%85%B8%E4%B9%8B%E8%B7%AF%E2%80%94%E2%80%94s-plus%EF%BC%88%E8%A2%AB%EF%BC%89%E5%B9%B6%E8%B4%AD%E5%A4%A7%E4%BA%8B%E8%AE%B0/" rel='nofollow'>StatSci</a>公司运作，九十年代初转主<a href="http://en.wikipedia.org/wiki/Mathsoft" rel='nofollow'>MathSoft</a>，2001年公司改组，改名叫<a href="http://en.wikipedia.org/wiki/S-plus" rel='nofollow' rel='nofollow'>Insightful</a>，前年（2008），<a href="http://en.wikipedia.org/wiki/S-plus" rel='nofollow' rel='nofollow'>Insightful</a>又被BI产商<a href="http://www.tibco.com" rel='nofollow'>Tibco</a>收购，从此，江湖上再也听不到S-plus的名号，它被融入Tibco的一个叫TIBCO Spotfire的分析平台。</p>
<p>再说SPSS，它的历史最早，1968年就有第一个发行版，由当时斯坦福大学的研究生<a href="http://en.wikipedia.org/wiki/Norman_Nie" rel='nofollow'>Norman Nie</a>等人发明，原意是Statistical Package for the Social Sciences。1975年SPSS公司成立，1993年上市。2009年，SPSS公司被IBM以12亿美元收购。现在，这家公司称作&#8221;SPSS: An IBM Company&#8221;，那个软件，叫做PASW (Predictive Analytics SoftWare) 。我们默认的那个SPSS也已经不复存在。</p>
<p>2009年，SAS公司的全球收入是<a href="http://www.sas.com/news/preleases/2009financials.html" rel='nofollow'>23亿美元</a>，它创立于1976年，比SPSS公司还晚一年。SAS软件1972年就有一个较稳定的发行版。随着BO等BI公司、SPSS等数据分析工具提供商一个个被IT巨头收购，SAS现在是全球最大的<strong>独立的</strong>BI/分析厂商，迄今没有上市。</p>
<h2>2. R和SAS</h2>
<p>这里要单独说下R。R现在被认为是SAS的一个潜在<a href="http://cos.name/2009/01/r-and-sas-new-york-times/" rel='nofollow'>竞争者</a>。SAS公司在细分市场上的主要竞争对手是SAP、Oracle、IBM、Microsoft、Teradata、SunGard、Unica等IT厂商。R对SAS的（潜在）威胁，不是体现在软件本身，而是体现在用户尤其是高校用户上。前面提到，R现在是学院里的标准统计语言。随便揪一个统计系的学生问：“为什么学R”。答：“因为课程项目用。”“为什么课程项目用？”答：“因为老师用。”或者“因为谢益辉在用。”</p>
<p>那我们再问R的传道者像<a href="http://www.yihui.name/" rel='nofollow'>谢益辉</a>，“为什么用R？”答：“因为R开源”、“因为R统计功能强大，算法日新月异”、“因为某某大佬用R”等等。——通常，你不会因为，比如“R比SAS好”便去学R，或者“SAS比R好”便去学SAS。但是，假如一个人的时间精力只允许他/她学一门语言，那么，由于学院派益辉同学等的大声疾呼，R的确抢走了SAS的很多高校用户。但如果一个在校生还有额外的时间精力，而且他的志向不限于学院，那么，他或许应该再听听工业界的呼吁。</p>
<p>前面提到“算法日新月异”是R的一个优势，这对学院研究颇有吸引力，但工业界相对就保守些，对新算法的需求就小些。——平常听起来“保守”似乎是一个不太积极向上的词，但想想，一个法官应该是保守的，在统计学的假设检验里，遵守的其实也是一个<a href="http://cos.name/2008/12/decision-and-risk/" rel='nofollow'>保守原则</a>。举个例子，在学院研究中，Bayesian（贝叶斯分析）在概念上已经不是那么新潮了，但在医药行业（就是那个由保守的药监局如FDA监管的行业），现在用的还是传统的Frequentist方法（参见ICH E9，<em><a href="http://www.ich.org/LOB/media/MEDIA485.pdf" rel='nofollow'>Statistical Principles for Clinical Trials</a></em>）。学院里的优势不必然是工业界的优势，那么你为什么不额外再学一门SAS，这个工业界的金标准？以前说过，R的不足刚好是SAS所长，反之亦然。</p>
<p>又，有在校生说，R免费，而SAS是商业软件，故学R，——这是一个不成熟的、人云亦云的说法。你在学校实验室能免费学到SAS，以后你的东家自然会为SAS软件买单。费用不是你应该考虑的问题。</p>
<h2>3. SAS可以作为一门职业</h2>
<p>从实际的角度来说，有一个工种就叫做SAS程序员(SAS Programer, 或叫做Statistical SAS Programmer、Statistical Analyst)。在全球最大的求职网站<a href="http://www.monster.com" rel='nofollow'>www.monster.com</a>，分别以SAS等作为skill关键词，搜索结果如下（测试时间：2010-04-13，你现在看到的会有细微的差别）：</p>
<blockquote><p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?tjt=sas&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=sas%20&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>1645 SAS jobs</a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?q=matlab&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=matlab&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>577 Matlab jobs</a> <a href="http://jobsearch.monster.com/PowerSearch.aspx?q=R&amp;tjt=sas&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=spss&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow' rel='nofollow'></a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?q=R&amp;tjt=sas&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=spss&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>329 SPSS jobs </a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?tjt=sas&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=Fortran&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>87 Fortran jobs</a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?q=stata&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=stata&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>59 STATA jobs</a> <a href="http://jobsearch.monster.com/PowerSearch.aspx?q=stata&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=Maple&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow' rel='nofollow'></a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?q=stata&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=Maple&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>59 Maple jobs</a></strong></p>
<p><strong><a href="http://jobsearch.monster.com/PowerSearch.aspx?q=stata&amp;rad=20&amp;rad_units=miles&amp;tm=60#q=Mathematica&amp;rad=20&amp;rad_units=miles&amp;tm=60" rel='nofollow'>24 Mathematica jobs</a></strong></p></blockquote>
<p>这是英语世界的大致情况。说说我们身边的机会。SAS使用者大多集中在医药、金融等行业。现在国际上的大药厂（辉瑞、拜耳、诺华，……）纷纷在中国开研发中心，对生物统计师（Biostatistician，包括统计师和程序员。程序员就是SAS程序员，而SAS编程也是统计师的基本要求之一）的需求渐长。在金融领域，拿我稍熟悉的信用评分领域来讲，熟悉SAS和数据挖掘的人才也很短缺。另外，广泛的机会还能在国内如火如荼的互联网公司和通信行业找到。</p>
<p>其实，即使不把SAS作为一门职业，对一份分析类的工作，你简历中出现SAS也会比出现其他类似的东西（Excel、……）更能吸引雇主的眼球。SAS被普遍认为是一种重量级的工具。 对于统计系的学生，我知道R是你的首选。你需要再学习一门SAS的理由是，SAS是工业界的流行语言。 对社会学、经济学等社科类的专业学生来说，你们需要学习SAS，还有一个额外的理由，SAS会让你的背景显得更硬朗一些，大白话就是说，能让文科气息稍微淡一些。 对IT类学生来说，学习SAS不会占用你太多时间，然后在就业市场，你的选择会宽广很多。<em><span style="font-size: xx-small;">（待续）</span></em></p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/08/econ-software-sas/" title="我的求学之路：经济学、软件工程、SAS">我的求学之路：经济学、软件工程、SAS</a> (31)</li><li><a href="http://cos.name/2008/11/how-to-learn-statistics-by-jthu/" title="如何学习统计学，或我的学习之路——初学者写给初学者">如何学习统计学，或我的学习之路——初学者写给初学者</a> (8)</li><li><a href="http://cos.name/2010/09/3rd-bbf/" title="北京数据管理与生物统计论坛（BBF）第三次聚会见闻录">北京数据管理与生物统计论坛（BBF）第三次聚会见闻录</a> (6)</li><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/my-experience-with-statistics-by-chongjie-liu/" title="刘重杰：和统计接触的经历">刘重杰：和统计接触的经历</a> (4)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >Sonnets</a> : <a class="comment_content" href="http://cos.name/2010/04/think-sas-1/#comment-1601" title="View the entire comment by Sonnets" >同意，工具就是工具，我们应该主导工具，而不是工具主导我们。该用什么就用什么，学起来都挺容易的。不过可...</a></li>
<li><a class="commentor" href="" >oloolo</a> : <a class="comment_content" href="http://cos.name/2010/04/think-sas-1/#comment-1595" title="View the entire comment by oloolo" >本菜SAS，R双修，深感此类争论没有必要。。。。
任何一个用好了，皆是屠龙刀。
请诸位埋头仔细研...</a></li>
<li><a class="commentor" href="http://hi.baidu.com/ghxandsky/" >ghxandsky</a> : <a class="comment_content" href="http://cos.name/2010/04/think-sas-1/#comment-1588" title="View the entire comment by ghxandsky" >dapangmao兄，很抱歉不能访问你的Blog，Google blogspot.com，Wall了...</a></li>
<li><a class="commentor" href="http://hi.baidu.com/ghxandsky/" >ghxandsky</a> : <a class="comment_content" href="http://cos.name/2010/04/think-sas-1/#comment-1587" title="View the entire comment by ghxandsky" >1991年，Linux面对Unix、*BSD等辈时，不见得当时的人能预见今天的Linux大规模应用。...</a></li>
<li><a class="commentor" href="http://hi.baidu.com/ghxandsky/" >ghxandsky</a> : <a class="comment_content" href="http://cos.name/2010/04/think-sas-1/#comment-1586" title="View the entire comment by ghxandsky" >Fortran is one of All Evil Things.</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2010/04/think-sas-1/feed/</wfw:commentRss>
		<slash:comments>92</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>也谈提高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>用R也能做精算—actuar包学习笔记（一）</title>
		<link>http://cos.name/2009/11/a-tutorial-on-package-actuar-1/</link>
		<comments>http://cos.name/2009/11/a-tutorial-on-package-actuar-1/#comments</comments>
		<pubDate>Fri, 27 Nov 2009 04:24:55 +0000</pubDate>
		<dc:creator>李皞</dc:creator>
				<category><![CDATA[应用领域]]></category>
		<category><![CDATA[推荐文章]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[风险精算]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[损失分布]]></category>
		<category><![CDATA[精算]]></category>
		<category><![CDATA[风险理论]]></category>

		<guid isPermaLink="false">http://cos.name/?p=1648</guid>
		<description><![CDATA[本文是对R中精算学专用包actuar使用的一个简单教程。actuar项目开始于2005年，在2006年2月首次提供公开下载，其目的就是将一些常用的精算函数引入R系统。目前，提供的函数主要涉及风险理论，损失分布和信度理论。 如题所示，本文是我在学习actuar包过程中的学习笔记，主要涉及这个包中一些函数的使用方法和细节，对一些方法的结论也有稍许探讨，因此能简略的地方简略，而讨论的地方可能讲的会比较详细。闲话少提，下面正式开始学习！ 1、数据分组 分组数据是精算学中常用的数据格式，比如我们要把不同风险类别的人群进行分别统计。假设我们要把一组连续变量分为n组，显然需n+1个边界。 函数 gouped.data(Group = c(...), freq1 = c(...), freq2 = c(...), ..., right = TRUE, row.names = NULL) 使用注意： 1）  Group 是分组的临界值，freq1和freq2是对应组别的频数。Group，freq1和freq2可以随意命名，但是一定要把临界值向量放在第一个位置。 2）  Group向量要比freq向量多出一个长度。 3）  默认分组区间是左开右闭，如果想变为左闭右开可以设置right=FALSE。row.names可以自定义行的名称。 4）  返回的是一个数据框。特别要注意对第一列的处理。 &#62; x=grouped.data(Group= c(0, 25, 50, 100, 150,250, 500), Line.1 = c(30, 31, 57, 42, 65, 84), Line.2 = c(26, 33, 31, 19, 16, 11)) [...]]]></description>
			<content:encoded><![CDATA[<p>本文是对R中精算学专用包actuar使用的一个简单教程。actuar项目开始于2005年，在2006年2月首次提供公开下载，其目的就是将一些常用的精算函数引入R系统。目前，提供的函数主要涉及风险理论，损失分布和信度理论。</p>
<p>如题所示，本文是我在学习actuar包过程中的学习笔记，主要涉及这个包中一些函数的使用方法和细节，对一些方法的结论也有稍许探讨，因此能简略的地方简略，而讨论的地方可能讲的会比较详细。闲话少提，下面正式开始学习！<span id="more-1648"></span></p>
<h1>1、数据分组</h1>
<p>分组数据是精算学中常用的数据格式，比如我们要把不同风险类别的人群进行分别统计。假设我们要把一组连续变量分为n组，显然需n+1个边界。</p>
<p>函数</p>
<pre>gouped.data(Group = c(...), freq1 = c(...), freq2 = c(...),
    ..., right = TRUE, row.names = NULL)</pre>
<p>使用注意：</p>
<p>1）  Group 是分组的临界值，freq1和freq2是对应组别的频数。Group，freq1和freq2可以随意命名，但是一定要把临界值向量放在第一个位置。</p>
<p>2）  Group向量要比freq向量多出一个长度。</p>
<p>3）  默认分组区间是左开右闭，如果想变为左闭右开可以设置right=FALSE。row.names可以自定义行的名称。</p>
<p>4）  返回的是一个数据框。特别要注意对第一列的处理。</p>
<pre>&gt; x=grouped.data(Group= c(0, 25, 50, 100, 150,250, 500),
 	Line.1 = c(30, 31, 57, 42, 65, 84),
	Line.2 = c(26, 33, 31, 19, 16, 11))
&gt; x
       Group Line.1 Line.2
1   (0,  25]     30     26
2  (25,  50]     31     33
3  (50, 100]     57     31
4 (100, 150]     42     19
5 (150, 250]     65     16
6 (250, 500]     84     11
&gt; x=grouped.data(Group= c(0, 25, 50, 100, 150,250, 500),
	Line.1 = c(30, 31, 57, 42, 65, 84),
	Line.2 = c(26, 33, 31, 19, 16, 11),
	right=F,row.names=LETTERS[1:6])
&gt; x
       Group Line.1 Line.2
A   [0,  25)     30     26
B  [25,  50)     31     33
C  [50, 100)     57     31
D [100, 150)     42     19
E [150, 250)     65     16
F [250, 500)     84     11</pre>
<p>提取子总体</p>
<pre>&gt; x[1,]
     Group Line.1 Line.2
A [0,  25)     30     26</pre>
<p>提取组频</p>
<pre>&gt; x[,2]
[1] 30 31 57 42 65 84</pre>
<p>提取边界值。如果引用第一列你期待会出现什么结果呢？</p>
<pre>&gt; x[,1]
[1]   0  25  50 100 150 250 500</pre>
<p>如同任何对数据框的操作，也可以对数据框中的数据进行修改。特别需要注意的是对第一列的修改，一定要明确指定分组区间的左右（或者中间）的边界值。如：</p>
<pre>&gt; x[1,1]=c(0,20)
&gt; x
       Group Line.1 Line.2
1   (0,  20]     30     26
2  (20,  50]     31     33
3  (50, 100]     57     31
4 (100, 150]     42     19
5 (150, 250]     65     16
6 (250, 500]     84     11
&gt; x[c(3, 4), 1]  x
       Group Line.1 Line.2
1   (0,  20]     30     26
2  (20,  55]     31     33
3  (55, 110]     57     31
4 (110, 160]     42     19
5 (160, 250]     65     16
6 (250, 500]     84     11</pre>
<p>如果只指定一个边界的话……</p>
<pre>&gt; x[1,1]=10
&gt; x
       Group Line.1 Line.2
1  (10,  10]     30     26
2  (10,  55]     31     33
3  (55, 110]     57     31
4 (110, 160]     42     19
5 (160, 250]     65     16
6 (250, 500]     84     11</pre>
<h1>2、分组统计</h1>
<p>1）函数mean()计算分组均值。等价于</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bj%3D1%7D%5Er%20n_j%28%5Cfrac%7Bc_%7Bj-1%7D%2Bc_j%7D%7B2%7D%29" title="\frac{1}{n}\sum_{j=1}^r n_j(\frac{c_{j-1}+c_j}{2})" alt="\frac{1}{n}\sum_{j=1}^r n_j(\frac{c_{j-1}+c_j}{2})" align="absmiddle" /></p>
<p>高阶矩的计算可以用函数emm(),见后文。</p>
<pre>&gt; x
       Group Line.1 Line.2
A   [0,  25)     30     26
B  [25,  50)     31     33
C  [50, 100)     57     31
D [100, 150)     42     19
E [150, 250)     65     16
F [250, 500)     84     11
&gt; mean(x)
   Line.1    Line.2
179.81392  99.90809</pre>
<p>Line.1的均值等价于：</p>
<pre>&gt; ((0+25)/2*30+(25+50)/2*31+(50+100)/2*57+(100+150)/2*42
       (150+250)/2*65+(250+500)/2*84)/sum(x[,2])
[1] 179.8139</pre>
<p>2）绘制直方图<br />
由于数据已经被划分好组别，因此R会应用数据框x的第一列作为组距的划分来绘制直方图，因此第一列一定要保留，这在绘制不等距直方图时是十分方便的。由于每次只能绘制一组频率，因此绘图时需要指定频率所在的列，如果不指定，默认绘制第一组频率（数据框的第二列）。</p>
<pre>&gt; layout(matrix(1:3,1,3))
&gt; hist(x[,-3],main='Histogram of freq.1')
&gt; hist(x[,-2],main='Histogram of freq.2')
&gt; hist(x,main='Histogram for unspecified x')</pre>
<p align="left"><img class="aligncenter size-full wp-image-1659" src="http://cos.name/wp-content/uploads/2009/11/image004.jpg" alt="image004" width="553" height="227" /></p>
<p>3）绘制累计频率图。如同对连续的随机变量可以绘制经验分布函数图一样，对于分组曲线也可以绘制“拱形图”（ogive），也就是累计频率曲线，它通过将分组边界值所对应的累计频率用直线连接起来得到。累计频率曲线的公式如下：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%5Ctilde%7BF%7D_n%28x%29%3D%5Cbegin%7Bcases%7D%0D%0A%0D%0A0%20%26amp%3B%20x%5Cleq%20c_0%20%5C%5C%0D%0A%0D%0A%5Cfrac%7B%28c_j-x%29F_n%28c_%7Bj-1%7D%29%2B%28x-c_%7Bj-1%7D%29F_n%28c_j%29%7D%7Bc_j-c_%7Bj-1%7D%7D%20%26amp%3B%20c_%7Bj-1%7D%26lt%3Bx%5Cleq%20c_j%20%5C%5C%0D%0A%0D%0A1%20%26amp%3B%20x%26gt%3Bc_r%0D%0A%0D%0A%5Cend%7Bcases%7D%0D%0A%0D%0A" title="&#13;&#10;\tilde{F}_n(x)=\begin{cases}&#13;&#10;&#13;&#10;0 &amp;amp; x\leq c_0 \\&#13;&#10;&#13;&#10;\frac{(c_j-x)F_n(c_{j-1})+(x-c_{j-1})F_n(c_j)}{c_j-c_{j-1}} &amp;amp; c_{j-1}&amp;lt;x\leq c_j \\&#13;&#10;&#13;&#10;1 &amp;amp; x&amp;gt;c_r&#13;&#10;&#13;&#10;\end{cases}&#13;&#10;&#13;&#10;" alt="&#13;&#10;\tilde{F}_n(x)=\begin{cases}&#13;&#10;&#13;&#10;0 &amp;amp; x\leq c_0 \\&#13;&#10;&#13;&#10;\frac{(c_j-x)F_n(c_{j-1})+(x-c_{j-1})F_n(c_j)}{c_j-c_{j-1}} &amp;amp; c_{j-1}&amp;lt;x\leq c_j \\&#13;&#10;&#13;&#10;1 &amp;amp; x&amp;gt;c_r&#13;&#10;&#13;&#10;\end{cases}&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p align="left">
<p align="left">函数ogive()返回的是一个阶梯函数对象(Step Function Class)，也就是说返回的是一个函数，给定函数的横坐标，就可以返回相对应的频率，这点和ecdf()是相同的。我们可以通过konts()返回阶梯函数对象的临界点，通过plot()绘制阶梯函数。</p>
<pre>&gt; Fnt  knots(Fnt)  #返回临界点
[1]   0  25  50 100 150 250 500
&gt; Fnt(knots(Fnt))   #返回临界点对应的累积频率值
[1] 0.00000000 0.09708738 0.19741100 0.38187702
     0.51779935 0.72815534 1.00000000
&gt; plot(Fnt)</pre>
<p><img class="aligncenter size-full wp-image-1660" src="http://cos.name/wp-content/uploads/2009/11/image008.jpg" alt="image008" width="271" height="271" /></p>
<h1>3、计算经验矩</h1>
<p>如果说均值函数mean()只能计算一阶矩，那么emm()函数则可以计算任意阶的经验原点矩。</p>
<p>首先引入actuar包中的两个数据集。其中dental是非分组数据，gdental是分组数据。</p>
<pre>&gt; data(dental)
&gt; dental
 [1]  141   16   46   40  351  259  317 1511  107  567
&gt; data(gdental)
&gt; gdental
          cj    nj
1      (0,  25] 30
2    ( 25,  50] 31
3    ( 50, 100] 57
4    (100, 150] 42
5    (150, 250] 65
6    (250, 500] 84
7   (500, 1000] 45
8  (1000, 1500] 10
9  (1500, 2500] 11
10 (2500, 4000]  3</pre>
<p>emm()函数可以计算任意阶经验原点矩，其使用方法是这样的:  emm(x,order=1)。其中，x可以是数据向量或者是矩阵，如果是分组数据，x也可以是由grouped.data()生成的数据框。order是阶数，可以赋值给它一个向量，这样就能一次性计算多个原点矩。</p>
<p>当为非分组数据时，计算的公式为：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0A%5Csum_%7Bj%3D1%7D%5En%20x_j%5Ek%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;\sum_{j=1}^n x_j^k&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;\sum_{j=1}^n x_j^k&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>当为分组数据时，计算的公式为：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0A%5Csum_%7Bj%3D1%7D%5Er%20n_j%5Cfrac%7B%28c_j%5E%7Bk%2B1%7D-c_%7Bj-1%7D%5E%7Bk%2B1%7D%29%7D%7Bn%2A%28k%2B1%29%2A%28c_j-c_%7Bj-1%7D%29%7D%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;\sum_{j=1}^r n_j\frac{(c_j^{k+1}-c_{j-1}^{k+1})}{n*(k+1)*(c_j-c_{j-1})}&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;\sum_{j=1}^r n_j\frac{(c_j^{k+1}-c_{j-1}^{k+1})}{n*(k+1)*(c_j-c_{j-1})}&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<pre>&gt; emm(dental,2)
[1] 293068.3
&gt; emm(gdental,1:3)
[1] 3.533399e+02 3.576802e+05 6.586332e+08</pre>
<p>elev()函数可以计算经验有限期望值（limited expected value）。使用方法是elev(x)：x可以是非分组数据，也可以是分组数据，如果是分组数据，默认以第一组频率为计算对象。</p>
<p>对于非分组数据，有限期望值的公式为：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0AE%5BX%5Cwedge%20u%5D%3Df%28u%29%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bj%3D1%7D%5En%5Cmin%28x_j%2Cu%29%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;E[X\wedge u]=f(u)=\frac{1}{n}\sum_{j=1}^n\min(x_j,u)&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;E[X\wedge u]=f(u)=\frac{1}{n}\sum_{j=1}^n\min(x_j,u)&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>对于分组数据，有限期望公式比较复杂，在此略去。</p>
<p>注意到，有限期望值是上限值u的函数。</p>
<pre>&gt; lev=elev(dental)
&gt; lev(knots(lev))
 [1]  16.0  37.6  42.4  85.1 105.5 164.5 187.7 197.9 241.1 335.5
&gt; lev2=elev(gdental)
&gt; par(mfrow=c(1,2))
&gt; plot(lev,type='o',pch=19)
&gt; plot(lev2,type='o',pch=19)</pre>
<p><img class="aligncenter size-full wp-image-1661" src="http://cos.name/wp-content/uploads/2009/11/image018.jpg" alt="image018" width="554" height="306" /></p>
<h1>4、分布拟合</h1>
<p>在R中，MASS包中的fitdistr()函数可以用极大似然估计，对数据进行分布拟合。在actuar()包中，mde()函数则提供了三种基于距离最小化的估计方法（minium distance estimates）。</p>
<p>1）  Cramér-von Mises方法（CvM）最小化理论分布函数和经验分布函数（对于分组数据是ogive）的距离。</p>
<p>未分组数据：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0Ad%28%5Ctheta%29%3D%5Csum_%7Bj%3D1%7D%5Er%20w_j%28F%28x_j%3B%5Ctheta%29-F_n%28x_j%29%29%5E2%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^r w_j(F(x_j;\theta)-F_n(x_j))^2&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^r w_j(F(x_j;\theta)-F_n(x_j))^2&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>分组数据：</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0Ad%28%5Ctheta%29%3D%5Csum_%7Bj%3D1%7D%5Erw_j%28F%28c_j%3B%5Ctheta%29-%5Ctilde%7BF%7D_n%28c_j%29%29%5E2%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^rw_j(F(c_j;\theta)-\tilde{F}_n(c_j))^2&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^rw_j(F(c_j;\theta)-\tilde{F}_n(c_j))^2&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>在这里，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize F%28x%3B%5Ctheta%29" title="F(x;\theta)" alt="F(x;\theta)" align="absmiddle" />是理论分布函数，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %2Ftheta" title="/theta" alt="/theta" align="absmiddle" />是其参数；<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize F_n%28x%29" title="F_n(x)" alt="F_n(x)" align="absmiddle" />是经验分布函数ecdf；<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Ctilde%7BF%7D_n%28x%29" title="\tilde{F}_n(x)" alt="\tilde{F}_n(x)" align="absmiddle" />是累积频率函数ogive；<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize w_j" title="w_j" alt="w_j" align="absmiddle" />是权重，默认都取1。</p>
<p>2）修正卡方法仅应用于分组数据，通过最小化各组期望频数与实际观测频数的平方误差得到。</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0Ad%28%5Ctheta%29%3D%5Csum_%7Bj%3D1%7D%5Erw_j%5Bn%28F%28c_j%3B%5Ctheta%29-F%28c_%7Bj-1%7D%3B%5Ctheta%29%29-n_j%5D%5E2%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^rw_j[n(F(c_j;\theta)-F(c_{j-1};\theta))-n_j]^2&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^rw_j[n(F(c_j;\theta)-F(c_{j-1};\theta))-n_j]^2&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>其中，<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n%3D%5Csum_%7Bj%3D1%7D%5Enn_j" title="n=\sum_{j=1}^nn_j" alt="n=\sum_{j=1}^nn_j" align="absmiddle" />,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize w_j" title="w_j" alt="w_j" align="absmiddle" />默认情况下为<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n_j%5E%7B-1%7D" title="n_j^{-1}" alt="n_j^{-1}" align="absmiddle" />。</p>
<p>3）LAS法（layer average severity）也仅应用于分组数据。通过最小化各组内的理论和经验有限期望函数的平方误差得到。</p>
<p><img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %0D%0A%0D%0Ad%28%5Ctheta%29%3D%5Csum_%7Bj%3D1%7D%5Er%20w_j%28LAS%28c_%7Bj-1%7D%2Cc_j%3B%5Ctheta%29-L%5Ctilde%7BA%7DS_n%28c_%7Bj-1%7D%2Cc_j%29%29%5E2%0D%0A%0D%0A" title="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^r w_j(LAS(c_{j-1},c_j;\theta)-L\tilde{A}S_n(c_{j-1},c_j))^2&#13;&#10;&#13;&#10;" alt="&#13;&#10;&#13;&#10;d(\theta)=\sum_{j=1}^r w_j(LAS(c_{j-1},c_j;\theta)-L\tilde{A}S_n(c_{j-1},c_j))^2&#13;&#10;&#13;&#10;" align="absmiddle" /></p>
<p>其中<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize LAS%28x%2Cy%29%3DE%28X%5Cwedge%20y%29-E%28X%5Cwedge%20x%29" title="LAS(x,y)=E(X\wedge y)-E(X\wedge x)" alt="LAS(x,y)=E(X\wedge y)-E(X\wedge x)" align="absmiddle" />,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize L%5Ctilde%20AS_n%28x%2Cy%29%3D%5Ctilde%20E_n%5BX%5Cwedge%20y%5D-%5Ctilde%20E_n%5BX%5Cwedge%20x%5D" title="L\tilde AS_n(x,y)=\tilde E_n[X\wedge y]-\tilde E_n[X\wedge x]" alt="L\tilde AS_n(x,y)=\tilde E_n[X\wedge y]-\tilde E_n[X\wedge x]" align="absmiddle" />,<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize E%28%29" title="E()" alt="E()" align="absmiddle" />是理论分布的有限期望函数，而<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize %5Ctilde%20E_n" title="\tilde E_n" alt="\tilde E_n" align="absmiddle" />是经验分布的有限期望函数。<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize w_j" title="w_j" alt="w_j" align="absmiddle" />默认情况下为<img src="http://www.forkosh.dreamhost.com/mimetex.cgi?\normalsize n_j%5E%7B-1%7D" title="n_j^{-1}" alt="n_j^{-1}" align="absmiddle" />。</p>
<p>函数调用optim()函数做最优化，其语法为：</p>
<pre>mde(x, fun, start, measure = c("CvM", "chi-square", "LAS"),
      weights = NULL, ...)</pre>
<p>其中：<br />
1）    x是分组的或未分组的数据。<br />
2）    fun是待拟合的分布，CvM法和修正卡方法需要指定分布函数：dfoo。LAS法需要指定理论有限期望函数。</p>
<blockquote><p>Tips：R中对于一些分布foo提供了d，p，q，r四种函数，分别是密度函数，分布函数，分布函数的反函数和生成该分部的随机数。在actuar包中，除了提供R中原先没有但在精算研究中很重要的分布（比如pareto分布）的上述函数外，还对一些连续分布（注意是连续分布！）额外提供了m、lev和mgf三种函数，m是计算理论原点矩，lev是计算有限期望函数，mgf是计算矩母函数。对于经验数据，如上面介绍actuar包中提供了emm()和lev()来计算经验原点矩和经验有限期望函数。</p></blockquote>
<p>3）    start指定参数初始值。形式必须以列表的形式，形式可以见例子，有几个参数就要指定几个初始值。<br />
4）    measure是指定方法。weight指定权重，否则采用默认权重。<br />
5）    &#8230;是其他参数，可以指定optim()函数中的参数，比如使用L-BFGS-B方法进行优化可以添加参数method=“L-BFGS-B”。<br />
我们可以对上面的gdental数据进行分布拟合。</p>
<pre>&gt; mde(gdental,pexp,start=list(rate=1/200),measure="CvM")
     rate
 0.003551270 

   distance
 0.002841739
Warning message:
In optim(x = c(0, 25, 50, 100, 150, 250, 500, 1000, 1500, 2500,  :
  one-diml optimization by Nelder-Mead is unreliable: use optimize
&gt; hist(gdental)
&gt; theta=1/200
&gt; curve(theta*exp(1)^(-theta*x),from=0,to=4000,add=T,col='red')</pre>
<p><img class="aligncenter size-full wp-image-1723" src="http://cos.name/wp-content/uploads/2009/11/clip_image0021.jpg" alt="clip_image002" width="271" height="271" /><br />
在此，我们感兴趣的是将基于距离的分布拟合方法与极大似然估计的参数估计效果进行以下对比。因此不妨做一个实验：<br />
简单起见，先从单参数拟合问题开始，这是一个一维优化问题。<br />
首先生成50组来自于rate=1的指数分布随机数，每组的个数都为10。然后，对于每一组随机数，分别用基于距离的估计方法和极大似然估计进行参数估计，将50次模拟结果的均值和标准差记录下来。之后，将随机数的个数由10增加到20，30…200，重复之前的过程。最终得到的结果如下图：</p>
<p><img class="aligncenter size-full wp-image-1732" src="http://cos.name/wp-content/uploads/2009/11/clip_image0022.jpg" alt="clip_image002" width="553" height="319" /></p>
<p>可以看出，在单参数估计中，尤其是在样本量较大时，两种方法估计的结果相差不大，而极大似然估计的方差要比基于距离的估计方差略小。那么，两种方法对于异常值的稳健性如何呢？在上面生成的所有组随机数中，剔除两个指数分布随机数，再混入两个来自[200,300]均匀分布的随机数，再重新对参数进行估计，结果很明显，基于距离的估计方法估计的结果很稳定，而极大似然估计的参数结果受异常值的影响很大！</p>
<p><img class="aligncenter size-full wp-image-1662" src="http://cos.name/wp-content/uploads/2009/11/image052.jpg" alt="image052" width="553" height="324" /></p>
<p>因此，对于经常存在异常值的损失数据，使用基于距离的分布拟合方法往往更加稳健。</p>
<p>对于两参数的估计，使用mde()函数经常会报错，通常的解决办法是估计参数的对数形式，然后再取指数还原，由于参数的对数形式可以取负值，这样程序虽然也会优化失败，但要比不取对数时的可能性要小很多。</p>
<p>比如：</p>
<pre>&gt; pgammalog=function(x,logshape,logscale)
  {
	pgamma(x,exp(logshape),exp(logscale))
  }
&gt;
&gt; aa=rgamma(200,shape=3,scale=1)
&gt; estlog=mde(aa,pgammalog,start=list(logshape=1.3,logscale=0.2),
              measure='CvM',method='L-BFGS-B',lower=c(0.5,-0.5),
              upper=c(1,5,0.5))$estimate
&gt; exp(estlog)
 logshape  logscale
2.4873247 0.8404548</pre>
<p>(未完待续)</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/04/think-sas-1/" title="Think SAS(一)">Think SAS(一)</a> (92)</li><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/07/maximum-likelihood-estimation-in-r/" title="R中的极大似然估计">R中的极大似然估计</a> (2)</li><li><a href="http://cos.name/2009/07/studying-notes-on-oop-in-r/" title="R中面向对象编程方法">R中面向对象编程方法</a> (6)</li><li><a href="http://cos.name/2009/07/drawing-china-map-using-r/" title="用R软件绘制中国分省市地图">用R软件绘制中国分省市地图</a> (47)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >于怡</a> : <a class="comment_content" href="http://cos.name/2009/11/a-tutorial-on-package-actuar-1/#comment-1083" title="View the entire comment by 于怡" >其实这种商业的东西还是能够自己编程比较好，如果有现成的开源的release出来，肯定都是落伍了的呵呵...</a></li>
<li><a class="commentor" href="" >李皞</a> : <a class="comment_content" href="http://cos.name/2009/11/a-tutorial-on-package-actuar-1/#comment-1082" title="View the entire comment by 李皞" >原来是这样，受教了。
其实这个包主要是针对《loss models》这本书编的，所以在看这本书时配...</a></li>
<li><a class="commentor" href="" >于怡</a> : <a class="comment_content" href="http://cos.name/2009/11/a-tutorial-on-package-actuar-1/#comment-1081" title="View the entire comment by 于怡" >这个包主要针对loss model, risk theory, credibility
所涉及函数...</a></li>
<li><a class="commentor" href="" >huang shuai</a> : <a class="comment_content" href="http://cos.name/2009/11/a-tutorial-on-package-actuar-1/#comment-1053" 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-tutorial-on-package-actuar-1/#comment-1051" title="View the entire comment by 魏太云" >黄兄可是本次会议“两会代表”说法的始作俑者啊，让大家开心了好久:)</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/11/a-tutorial-on-package-actuar-1/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>分层线性模型软件HLM6.0操作简介</title>
		<link>http://cos.name/2009/09/guide-to-hlm/</link>
		<comments>http://cos.name/2009/09/guide-to-hlm/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 02:28:45 +0000</pubDate>
		<dc:creator>陈堰平</dc:creator>
				<category><![CDATA[统计软件]]></category>
		<category><![CDATA[HLM]]></category>
		<category><![CDATA[分层线性模型]]></category>

		<guid isPermaLink="false">http://cos.name/?p=610</guid>
		<description><![CDATA[分层线性模型 (Hierarchical linear Model，简称 HLM，又称多层线性模型，Multilevel Linear Model)，HLM6.0 是分层线性模型软件，包含线性和非线性部分，可以读取大部份统计软件的数据如 SPSS, SAS, SYSTAT及STATA等等。HLM常用于社会科学和行为科学，因为它常有嵌套结构(Nested Structure)的数据，因此需用次模型(Sub-Model)或分层线性模型(Hierarchical Model)，HLM就是设计来专门解决此类问题的，HLM提供的模型包括2-level models、3-level models、Hierarchical Generalized Linear Models (HGLM)和Hierarchical Multivariate Linear Models (HMLM)等。 下面是中国人民大学统计学院分层线性模型的课件，主要内容为HLM6.0的操作 下载地址：http://cos.name/wp-content/uploads/2009/09/intro2HLM6.zip 相关文章统计学专业应该使用什么样的统计软件（写给在统计学院学习的学弟学妹之四） (37)最新评论谢益辉 : 非常非常感谢你的解释，有了这样一个大致概念之后再看书就好多了，对我的学习来说，很多统计模型都是因为没... huang shuai : 恩。。 发现我答非所问了　赫赫 你问的问题透露出你的目的可能是要去研究几个变量之间的关系，或者一... 谢益辉 : 谢谢你的文献，我找到这本书了，回头读一读：） 谢益辉 : ``Rare cases in certain units'' sounds like a reas... 谢益辉 : 这个例子只是说明了一个控制变量的问题，我以前也写过类似的例子：http://yihui.name/c...]]></description>
			<content:encoded><![CDATA[<p>分层线性模型 (Hierarchical linear Model，简称 HLM，又称多层线性模型，Multilevel Linear Model)，HLM6.0 是分层线性模型软件，包含线性和非线性部分，可以读取大部份统计软件的数据如 SPSS, SAS, SYSTAT及STATA等等。HLM常用于社会科学和行为科学，因为它常有嵌套结构(Nested Structure)的数据，因此需用次模型(Sub-Model)或分层线性模型(Hierarchical Model)，HLM就是设计来专门解决此类问题的，HLM提供的模型包括2-level models、3-level models、Hierarchical Generalized Linear Models (HGLM)和Hierarchical Multivariate Linear Models (HMLM)等。</p>
<p>下面是中国人民大学统计学院分层线性模型的课件，主要内容为HLM6.0的操作</p>
<p>下载地址：http://cos.name/wp-content/uploads/2009/09/intro2HLM6.zip</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2008/11/which-statistical-software-should-we-use/" title="统计学专业应该使用什么样的统计软件（写给在统计学院学习的学弟学妹之四）">统计学专业应该使用什么样的统计软件（写给在统计学院学习的学弟学妹之四）</a> (37)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/09/guide-to-hlm/#comment-839" title="View the entire comment by 谢益辉" >非常非常感谢你的解释，有了这样一个大致概念之后再看书就好多了，对我的学习来说，很多统计模型都是因为没...</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/09/guide-to-hlm/#comment-837" title="View the entire comment by huang shuai" >恩。。
发现我答非所问了　赫赫
你问的问题透露出你的目的可能是要去研究几个变量之间的关系，或者一...</a></li>
<li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/09/guide-to-hlm/#comment-836" title="View the entire comment by 谢益辉" >谢谢你的文献，我找到这本书了，回头读一读：）</a></li>
<li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/09/guide-to-hlm/#comment-835" title="View the entire comment by 谢益辉" >``Rare cases in certain units'' sounds like a reas...</a></li>
<li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/09/guide-to-hlm/#comment-834" title="View the entire comment by 谢益辉" >这个例子只是说明了一个控制变量的问题，我以前也写过类似的例子：http://yihui.name/c...</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/09/guide-to-hlm/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>我的求学之路：经济学、软件工程、SAS</title>
		<link>http://cos.name/2009/08/econ-software-sas/</link>
		<comments>http://cos.name/2009/08/econ-software-sas/#comments</comments>
		<pubDate>Sun, 09 Aug 2009 02:36:00 +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[COS]]></category>
		<category><![CDATA[SAS]]></category>
		<category><![CDATA[SAS程序员]]></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/2009/08/econ-software-sas/</guid>
		<description><![CDATA[这个青年的经历，只代表他个人，没有任何群体的意义。 我想写下一段自白,这自白既是我个人的,也具有普遍意义,因为一个人经历过的事情所有的人都可以经历。 /*跟武汉博文视点合作，召集些身边的朋友，2009应届生，计算机背景，在毕业之前，讲讲自己求学、实习、找工作等的经历与感悟，文章将由电子工业出版社结集出版，在今天秋季学期开学之前出来。我是主编，也是作者之一，刚好经历跟大伙有重叠：经济学、软件工程、SAS、统计学、数据挖掘，文章贴出来，大伙多拍砖头。文中我提到COS，COS让我长见识，又结识不少好朋友。*/ 想启蒙至今，我的学习重心从文史哲转到经济学，最后以软件工程收场；在行业方面，在一家软件公司实习了一年多，找工作以药厂收场——用一个朋友的话讲，“背景是复杂得一塌糊涂”。虽然我常以“学一行，爱一行；做一行，爱一行”自勉，有时也不免回首，想想以前经历过的所有分岔口，玩味些那些没有走过的路，无论当时我多么坚决或者犹豫，一条路被选中，然后一路曲折至今。很多事情，很多选择，可能只有以后才能适合评说，现在我选择把它们记下来，在这么一个时点，我就要毕业，我有一个安身立命的去处，我有规划，但我不知道以后生活会给我什么样的分岔口，就跟我以前遭遇的一样。 ——————我的人生轨迹————— 项羽，“学书不成，去；学剑，又不成”。 —-《史记·项羽本纪 1.高中：文科生，喜文史 &#124; &#124;高考 / \ / \ 学文史不成，去 2.经济学，北京工商大学 &#124;考研 / \ / \ 学经济学不成，去 3.软件工程（金融信息工程），北京大学 &#124; 知识转型 / \ / \ 学C/C++、Java不成，去 攻SAS与信用评分、数据挖掘 &#124; &#124;实习 / \ / \ 4.SAS中国研发中心 &#124;工作 / \ / \ / \ 5. Sanofi Pasteur，SAS程序员 ——————我的人生轨迹————— 小学 我是在村小学、乡镇初中和县城高中完成大学之前的学业。家位于江西东北部，父母都是农民，小学文化（未毕业），对我的教育，强调的有几条，与人和气，不要打架，然后就是好好念书。在我们的社会，正如一些学者所说，“农民”更多是一个身份的指称，而不仅仅是一份职业。我愿意提起这个，因为，一旦开始思考，就会觉得没有什么会比它更重要。以前一个在学校负责“北大调查”的朋友跟我讲，在北大的所有在校生中，农村背景的，大概占10%，——大伙可以根据自己的经验，估计一下农村背景的学生在所有大学生中的比例。尽管被有意无意忽略，这却是中国的最大现实。 在农村的局限显而易见，所有的父母都期望他们的子女能够摆脱农民身份。在高三之前，我只做（坐）过一次火车，上大学才开始认真说普通话——或许还可以提一句，在大二，我开始穿上我人生中的第一条牛仔裤。农村有很多淳朴的东西，也有很多粗俗的东西，现在想来，跟童年的伙伴相比，我可能更敏感，更喜欢反观自身——我阅读，大量阅读。我父亲只有小学三年级的文化，但识字很多，喜欢读各种演义和建国历史（包括野史）。记得小时候在家里翻箱倒柜，也能翻出几本小说来，有一本是现在仍让我头大的《红楼梦》，后来就找不到了，可能让我给撕了折纸玩了吧。我读的第一本书，现在仍然印象深刻（好像自己大学以前读的每一本书，印象都比较深刻）。是小学二年级，一个雨天，在家里翻出一本破烂的《说岳全传》，前后都有大量缺页，我只能从朱仙镇读到风波亭，中间也偶有一两页找不到——真是悬念重重啊。虽然有大量生字，也顾不上查《新华字典》，窝在家里，读得是津津有味。来回翻几遍，记下来每一位武将趁手的兵刃，真是非常有成就感（这就是我最初的知识储备）。 自从有了这个体验，就跟“曾经沧海难为水”一样，就不愿意过没有书的日子了。家里没什么藏书，就向语文老师借，在村里淘——伙伴家里还是会有些印刷品的。那时，能够读到的书，以小说特别是通俗演义和武侠小说为主，我为数不多的几本言情，大概也是那时读的（《菟丝草》？）。《格林童话》之类说适合少年看的读物，我是在高中才补的。当时应付学业还比较轻松，所以没有什么来自父母和老师的压力，当然，武侠小说还是偷偷读的。我第一本武侠小说，大概是沧浪客的《一剑平江湖》，上册。高中时老师有一事比较头疼，一些喜欢读书的同学迷上了武侠小说，导致学业下降（那时网络不普及，让学生沉迷的大概只有游戏机和武侠小说）。那时我已经不读武侠，老师就喜欢拿我做例子，说我好读书而不读武侠云云。 一上来就是刀光剑影的阅读，现在真不忍心评价它对我的成长是好是坏。无论怎么样，它让我养成了读书的习惯，并且每到一个地方，都能找到有书的地方。那时候，是带汉字的纸条也爱读啊。 初中 [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>这个青年的经历，只代表他个人，没有任何群体的意义。</p>
<p>我想写下一段自白,这自白既是我个人的,也具有普遍意义,因为一个人经历过的事情所有的人都可以经历。</p></blockquote>
<p>/*跟武汉博文视点合作，召集些身边的朋友，2009应届生，计算机背景，在毕业之前，讲讲自己求学、实习、找工作等的经历与感悟，文章将由电子工业出版社结集出版，在今天秋季学期开学之前出来。我是主编，也是作者之一，刚好经历跟大伙有重叠：经济学、软件工程、SAS、统计学、数据挖掘，文章贴出来，大伙多拍砖头。文中我提到COS，COS让我长见识，又结识不少好朋友。*/</p>
<p>想启蒙至今，我的学习重心从文史哲转到经济学，最后以软件工程收场；在行业方面，在一家软件公司实习了一年多，找工作以药厂收场——用一个朋友的话讲，“背景是复杂得一塌糊涂”。虽然我常以“学一行，爱一行；做一行，爱一行”自勉，有时也不免回首，想想以前经历过的所有分岔口，玩味些那些没有走过的路，无论当时我多么坚决或者犹豫，一条路被选中，然后一路曲折至今。很多事情，很多选择，可能只有以后才能适合评说，现在我选择把它们记下来，在这么一个时点，我就要毕业，我有一个安身立命的去处，我有规划，但我不知道以后生活会给我什么样的分岔口，就跟我以前遭遇的一样。</p>
<pre>——————我的人生轨迹—————

项羽，“学书不成，去；学剑，又不成”。

                      —-《史记·项羽本纪

1.高中：文科生，喜文史
              |
              |高考
            /    \
           /      \
学文史不成，去     2.经济学，北京工商大学
                   |考研
                   / \
                 /   \
学经济学不成，去     3.软件工程（金融信息工程），北京大学
                           | 知识转型
                          / \
                         /   \
学C/C++、Java不成，去        攻SAS与信用评分、数据挖掘
                                     |
                                     |实习
                                   / \
                                 /    \
                                      4.SAS中国研发中心
                                           |工作
                                          / \
                                       /       \
                                    /             \
                                          5. Sanofi Pasteur，SAS程序员
——————我的人生轨迹—————</pre>
<p><span id="more-1416"></span></p>
<p><strong>小学</strong></p>
<p>我是在村小学、乡镇初中和县城高中完成大学之前的学业。家位于江西东北部，父母都是农民，小学文化（未毕业），对我的教育，强调的有几条，与人和气，不要打架，然后就是好好念书。在我们的社会，正如一些学者所说，“农民”更多是一个身份的指称，而不仅仅是一份职业。我愿意提起这个，因为，一旦开始思考，就会觉得没有什么会比它更重要。以前一个在学校负责“北大调查”的朋友跟我讲，在北大的所有在校生中，农村背景的，大概占10%，——大伙可以根据自己的经验，估计一下农村背景的学生在所有大学生中的比例。尽管被有意无意忽略，这却是中国的最大现实。</p>
<p>在农村的局限显而易见，所有的父母都期望他们的子女能够摆脱农民身份。在高三之前，我只做（坐）过一次火车，上大学才开始认真说普通话——或许还可以提一句，在大二，我开始穿上我人生中的第一条牛仔裤。农村有很多淳朴的东西，也有很多粗俗的东西，现在想来，跟童年的伙伴相比，我可能更敏感，更喜欢反观自身——我阅读，大量阅读。我父亲只有小学三年级的文化，但识字很多，喜欢读各种演义和建国历史（包括野史）。记得小时候在家里翻箱倒柜，也能翻出几本小说来，有一本是现在仍让我头大的《红楼梦》，后来就找不到了，可能让我给撕了折纸玩了吧。我读的第一本书，现在仍然印象深刻（好像自己大学以前读的每一本书，印象都比较深刻）。是小学二年级，一个雨天，在家里翻出一本破烂的《说岳全传》，前后都有大量缺页，我只能从朱仙镇读到风波亭，中间也偶有一两页找不到——真是悬念重重啊。虽然有大量生字，也顾不上查《新华字典》，窝在家里，读得是津津有味。来回翻几遍，记下来每一位武将趁手的兵刃，真是非常有成就感（这就是我最初的知识储备）。</p>
<p>自从有了这个体验，就跟“曾经沧海难为水”一样，就不愿意过没有书的日子了。家里没什么藏书，就向语文老师借，在村里淘——伙伴家里还是会有些印刷品的。那时，能够读到的书，以小说特别是通俗演义和武侠小说为主，我为数不多的几本言情，大概也是那时读的（《菟丝草》？）。《格林童话》之类说适合少年看的读物，我是在高中才补的。当时应付学业还比较轻松，所以没有什么来自父母和老师的压力，当然，武侠小说还是偷偷读的。我第一本武侠小说，大概是沧浪客的《一剑平江湖》，上册。高中时老师有一事比较头疼，一些喜欢读书的同学迷上了武侠小说，导致学业下降（那时网络不普及，让学生沉迷的大概只有游戏机和武侠小说）。那时我已经不读武侠，老师就喜欢拿我做例子，说我好读书而不读武侠云云。</p>
<p>一上来就是刀光剑影的阅读，现在真不忍心评价它对我的成长是好是坏。无论怎么样，它让我养成了读书的习惯，并且每到一个地方，都能找到有书的地方。那时候，是带汉字的纸条也爱读啊。</p>
<p><strong>初中</strong></p>
<p>初中比较幸运。在我那乡镇中学，居然有一个不对学生开放的图书室，管理员正好是我的语文老师，于是就有自由出入图书室的特权了。这时读的书，就比较文艺一些，以散文与诗歌为主，语言比较精致，就常常是一本书一本书抄下来。那阵子开始接触鲁迅、林语堂、胡适、梁实秋、梁遇春、哈代、毛姆等作家，还包括一些当时比较知名，现在可能不怎么闻名的，比如刘定中、徐刚、乔麦等等，乔麦是做报告文学的，徐刚写所谓九行诗，刘定中有一部散文诗集。</p>
<p>有过农村中学读书经历的朋友可能都有共识，那阵子的中学真是比较乱，打架的事比较多。那时我忙于抄写《朦胧诗集》之类的东西，心里有许多向往的东西，其他事就顾及不上了。</p>
<p>整个初中，就买过一本书，托在县城读书的朋友，带回一本《水浒传》，岳麓书社的普及本，十六块钱。</p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong>高中</strong></p>
<p>书一路读过来，到高中就有偏科的倾向，后来索性就转读文科。高中是自己读书的黄金时期，现在都觉得是把所有够得着的地方都淘遍了：校图书馆、朋友和亲戚家的私人藏书、县城所有的书店所有的书摊所有的报刊亭，还去过市里的几家书店，来过北京一次（第一次坐火车那次），在海淀图书城的中国书店买了几本哲学历史书回来。以前写过一系列博文，甚至列出了自己在高中读过的近百本书和杂志的名字，包括每本书的来源，是来自书店、图书馆还是借自个人（<em>具体见<a href="http://tinyurl.com/cfl9cw" rel='nofollow'>这里</a></em>）。那时住校，每个月可以向家里要些生活费。经常省下几顿，留下钱来买些书，但也还在抄书，以古文为主，《论语》、《古文观止》之类。高中毕业时，手头居然也有一柜子的藏书。</p>
<p>大学我念的是经济学，其实也不突兀。美国计量经济学家赫克曼和麦克法登得诺贝尔奖那年，学校旁边的邮政报刊亭不知道怎么就出现了一本《读书》杂志（的确只是一本），刚好有对他们的介绍。这新的领域，对我也是有很大的吸引力。以后读书，就觉得旁边也居然有好些经济学相关的材料，除了《读书》杂志经常刊登些，《青年文摘》、《读者》也还会有些类似《爱情经济学》的经济学随笔。</p>
<p>不过总的来说，高中我对自己的期望，还是人文方面的作家。他们的作品和生平，给我非常多的激励。</p>
<p><strong>本科，经济学，北京工商大学</strong></p>
<p>本科我在北京工商大学念经济学。第一志愿是北大中文系，算是我人生第一个遗憾吧。大一我还准备过一段时间，要考北大哲学系的研究生。现在还偶尔胡思乱想，我的气质和兴趣，在文科方面，说不准会有更大的发展呢。高中抄过一首美国诗人弗罗斯特的《未走过的路》，现在读来，仍然唏嘘不已：</p>
<blockquote><p>深黄的林子里有两条岔开的路，<br />
很遗憾，我，一个过路人，<br />
没法同时踏上两条征途，<br />
伫立好久，我向一条路远远望去，<br />
直到它打弯，视线被灌木丛挡住。</p>
<p>于是我选了另一条，不比那条差，<br />
也许我还能说出更好的理由，<br />
因为它绿草茸茸，等待人去践踏——<br />
其实讲到留下了来往的足迹，<br />
两条路，说不上差别有多大。</p>
<p>那天早晨，有两条路，相差无几，<br />
都埋在还没被踩过的落叶底下。<br />
啊，我把那第一条路留给另一天！<br />
可我知道，一条路又接上另一条，<br />
将来能否重回旧地，这就难言。</p>
<p>隔了多少岁月，流逝了多少时光，<br />
我将叹一口气，提起当年的旧事：<br />
林子里有两条路，朝着两个方向，<br />
而我——我走上一条更少人迹的路，<br />
于是带来完全不同的一番景象。</p></blockquote>
<p>大一时几乎以每天一本书的速度，想掏空学校图书馆人文社科类的好书——那时评判好书的标准也足够简单，一是成书久远，二就是来自大社。不过到大二，对念经济学的兴趣，就比较坚定了。那时开始到北大中国经济研究中心(CCER)听课，CCER当时是中国所有经济学学子向往的地方。现我在北大读研究生，说起来，在北大校园停留的时间，还真没有本科时多。我学校在航天桥，到北大有近二十里的路，大二和大三两年，几乎每周都骑车过去，一周大概两三天。</p>
<p>大学时有印象的，是在位于白石桥的国家图书馆停留过不少时间，很多时候是跟女朋友一起，她在人大念中文。学校图书馆藏书比较少，里面几乎每一本社科类新书的书皮我都翻过。泡国图，我的成就是，把它的两个阅览室——一楼的社科室和六楼的文学室——所有的书皮也都摸过一遍。现在在书店，我也是喜欢在书架中穿梭，手指在书脊上一本本划过，感兴趣的就抽出来翻翻。——我现在对北大图书馆的挖掘，相比功夫下得不足。</p>
<p>大学时自己比较浮躁。我知道自己所处的环境不够好，也积极向最好的地方靠拢，比如坚持去CCER听课。但心里很多东西，都割舍不下，像对文史哲等的喜好，贪多务得，细大不捐，花的时间不会比经济学少。我爱好很广泛，但感兴趣的，可能并不是自己所擅长的——这个我到后来才慢慢体会到，不过已经付出了很多的时间和精力。考研我就一心冲着北大中国经济研究中心(CCER)，两次都被拒掉。这对我触动很大，很长一段时间我都在想，自己到底适合做什么。</p>
<p>后来我又申请北大的深圳商学院以及软件与微电子学院。继续读商学院，可以延续我在经济学方面的训练，可是这方面，我已经有所怀疑。读软院，会是一个全新的开始，在技术方面会有所提升，而且其中的金融信息工程专业，还可以与我以前的教育背景交叉，但风险是，我一个文科生，在技术领域，到底能够走多远，这个选择会不会只是一个折腾？</p>
<p>这两个选择，几乎没有可比性，不可能精确地估计出它们的利弊。有时我想，（像这样比较困难的）决策不是“全面地”做出来的，而（可能）是“偏颇地”做出来的。综合考虑各种因素，你无法得出一个让自己信服的方案：考虑这个因素，我会继续读经济学，但考虑到另一个因素，读软件工程可能就是很好的选择。商学院还是软件学院？把它们各自的利弊摆在一起，我真是不好抉择。最后选择软院，真的是“偏颇”地做出选择的，不是因为我考虑到软院对对我更好，而是因为，我就一个劲想着我读软院对我知识体系带来的提升，我在技术领域可能的突破——这些也让我激动不已。商学院也很好，不过就是另一番景象了——我心里又在默念弗罗斯特的《未走过的路》。我偶尔想那些为走过的路，不是因为我后悔现在走的路，而是因为，这人生的种种可能，玩味起来，感触就深。</p>
<p>我本科的知识积累，对研究生的课程，有用的是，数学和统计学，还有金融学的基础知识。可能最重要的是，我对很多科目都感兴趣，虽然没接触过，但我不排斥计算机的相关课程。</p>
<p><strong>研究生，软件工程，北京大学</strong></p>
<p>2006年9月开始了我的软院求学历程。第一个挑战是：我该如何在软院生存下去？我本科背景，计算机的底子只是会操作计算机。第一堂Java课上，如何设置和为什么要设置环境变量就让我困扰不已。我人生第一个&#8221;Hello World&#8221;，也是手慌脚乱好几次才出来的。</p>
<p>我一边在开始学Java和C++，但心里也清楚，在这块，我很难赶上我身边已经有四年科班训练的同学。研一上学期有一门课让我看到了些曙光，万事达卡组织(MasterCard)的一位资深顾问冯慧博士给我们开信用评分课。申请贷款时，比如，申请信用卡（透支，可以看作是贷款），我们需要填上自己的各种信息。简单地说，信用评分技术就是利用这些申请资料和其他信息，通过各种数学与统计模型，对申请人的风险状况赋予一定的分数，以区别出哪些是好客户，哪些是坏客户。在金融领域，数据量都是非常庞大的，信用评分就是这么一个计算量密集的技术。在信用评分领域，一个标准语言就是SAS，一门解释性语言——有金融，有计算，这是我感兴趣的。</p>
<p>这门课我学得很认真，查看了不少资料，并写了不少信用评分技术相关的读书笔记与同学分享。另外就是自学SAS，它的语法结构类似C。虽然SAS跟Java/C++一样，我都是第一次接触，但我学习SAS的劲头和主动性就高多了。信用评分建模需要用到大量的数据挖掘算法，但我们金融信息工程系没有相关的课程。研一下学期，我就去语言信息工程系修了一门理论性较强的课程，《机器学习》，主要的应用背景是自然语言处理。那个课堂上，我大概是唯一的外系生。这门课我修得比较苦，成绩也不是很理想，就是及格那种。不过有了这门课的底子，接下来我修应用性的课程《数据挖掘与CRM》就轻松多了。</p>
<p>SAS在数据挖掘领域也是行业标准，对它的学习，也是一直没有断。同时我还花时间学习Java和C++，毕竟要拿的是软件工程的学位，不过掌握程度，自是比不上SAS。</p>
<p>这个时候我开始写跟SAS编程与数据挖掘相关的技术博客，记录我学习过程中的点点滴滴。很高兴有些朋友喜欢我的技术博客，有时候认识些新朋友，他提一句：我看过你的SAS博客，就觉得非常亲切。我还开始关注国内SAS相关的论坛（<a href="http://mysas.net" rel='nofollow'>mysas.net</a>、<a href="http://sasor.feoh.net" rel='nofollow'>sasor.feoh.net</a>等），又订阅了全球SAS用户最活跃的邮件列表SAS-L,偶尔也会加入讨论，尽量让自己往这个群体靠拢。从中结识不少志同道合的朋友，是非常愉快的一件事情。</p>
<p>通过网络认识了人大经济论坛的SAS版主朱杰，他是上海师范大学的一位青年教师，在培养学生学习SAS方面是不遗余力。一次聊天，他说，你喜欢SAS，又有金融背景，为什么不去直接跟清华金融系的朱世武老师学呢。于是，朱杰把我介绍给朱老师，我开始在清华旁听朱老师的SAS与金融计算的相关课程。</p>
<p>朱老师是几本SAS与金融计算相关书籍的作者，有统计学和金融工程的专业背景。朱老师说他用SAS几十年，什么工作都用SAS完成。通过课程学习和与朱老师的私下交流，当时自觉自己的SAS功底精进不少。</p>
<p>2007年我开始在学校主持北大SAS俱乐部，它是北大应用统计研究会下属的专业社团，也是国内高校第一个SAS社团，聚集了很多北大和周边高校SAS爱好者。我们通过培训、讲座等活动提高会员的SAS编程技能，促进会员与企业专家的沟通。另外，作为第一批会员，我还参加了“SAS用户与爱好者俱乐部”，它是一个SAS中国用户交流的非商业性组织，并致力于打造成一个SAS中国的user group。SAS在国内还不是很流行，能够投身于SAS推广的活动当中，心情是充满了自豪感。</p>
<p><strong>拓展：SAS、统计学、数据挖掘、商务智能(BI)</strong></p>
<p>在更为广泛的意义上，数据挖掘是商务智能(Business Intelligence, BI)的一个分支。BI行业的主要厂商是SAP、Oracle、IBM、Microsoft、SAS等。通过对SAS的了解，我对这整个行业也感兴趣起来，参加了国内一些活跃BI社区的线上线下交流活动，比如TTNN、Bicubes、Bihuman等，从中结识很多业界的朋友。另外，我还加入了国内高校里最活跃的统计社区，“统计之都”（<a href="cos.name" rel='nofollow'>cos.name</a>），并成为活跃作者之一。</p>
<p>学习技能，我从自己学习SAS、数据挖掘和统计学的经验中，可以总结几条：</p>
<p>学习期间，有任何问题，首先不要想着去论坛发问，教科书或Google能解决你大部分问题。或者干脆找到一个懂行的人，直接去问。人要爱惜自己的羽毛，在论坛问一些傻瓜问题，会损害你在社区的名誉。自己解决问题，会让自己变得更强壮。</p>
<p>还有就是不要过于积极地去网上找学习资料。资料太多，人生太短，对大部分人来说，需要的几本书，国内都有引进，找一本搁案头翻阅就是。几本难得的电子书，赶紧打印了出来，从此不再网上瞎整。以前我把硬盘塞满时，突然警惕。疯狂收集电子书自有乐趣，你会沉浸在这种乐趣之中，而忽略真正有用的东西和真正要做的事情。</p>
<p>最后多认识几位专业相关的朋友，让自己时刻清醒，自己还是这个领域的门外汉，以保持必要的谦逊。</p>
<p><strong>实习，SAS中国研发中心</strong></p>
<p>2007年年底，一次BI社区的线下聚会，我认识了一位在SAS中国研发中心工作的朋友。我向他问了很多关于SAS产品以及SAS公司的问题，聊得很愉快。一直向往SAS公司，没想到它离我也可以这么近。回来就想，为什么不尝试一下直接体验一下SAS公司呢？于是我就向SAS中国研发中心发了一封应聘实习生的求职信，很快得到回复。</p>
<p>面试官是SAS中国研发中心的总经理Alfred，他简单介绍了下自己就说我们来聊聊。接下来的时间，开始我在讲，讲自己的一些背景，尤其是学习SAS的经历，以及对SAS公司的关注和了解，然后是一些互动，Alfred介绍下公司以及中国研发中心的状况。最后Alfred问我C++学得怎么样。这个只好老实说我只是一个初学者。</p>
<p>整个过程很轻松，不像一般面试常有的challenge。我喜欢这样的氛围，或者向往这样的氛围，我们都是成年人，我们都是professional，气氛就应该是平等宽容轻松愉快的。</p>
<p>SAS是一家私人公司(private)，是全球商务智能与分析领域的领袖。在美国，有一句话：“如果你掌握了SAS编程，你将不愁失去工作。”SAS的专长在于数据整理和数据分析，包括统计分析、数据挖掘、预测建模、决策分析等。SAS程序员在国外，是跟C/C++程序员、Java程序员等并立的工种，市场需求比较大，尤其是医药行业、政府部门、金融机构等。我在那一年，几乎是全职状态。第一次开通自己的工作邮箱，真的可以算是自己学生生涯的一个分水岭：你要拿更稳健的做事方式要求自己，就跟自己的同事一样。我参与的是SAS信用评分解决方案的客户化测试项目——信用评分、数据挖掘，也正是我所感兴趣的。</p>
<p>值得一提的是，SAS公司的学习气氛很浓，经常有各种培训、workshop、knowledge share等活动。作为一名实习生，除了第一个月的全天候技术培训外，在以后的日子里，我还参加了商务英语写作、应用统计学、数据挖掘（讲师是印度的同事）等培训。另外，公司还提供大量的网络培训教程（Web Live Training），涉及SAS技术的方方面面，这个只能挑选自己感兴趣的领域去学了。在SAS技术方面，这一年能感觉到自己是越来越strong。</p>
<p>现在我虽然离开了SAS公司，有机会还是很乐意介绍些实习机会向师弟师妹推荐。在网上随时注意些老东家的新闻，并为曾经为它服务而感到自豪。</p>
<p><strong>工作，赛诺菲巴斯德(Sanofi Pasteur)</strong></p>
<p>2009年年初，当时我还在SAS中国研发中心实习，我收到一个猎头朋友的邮件，说一个什么world’s leading company需要SAS Programmer，问我感不感兴趣。</p>
<p>2008年秋季学期开始，我也在考虑工作的事情，当时金融危机已经影响到应届生就业市场了。一开始我也跟风，网申那些著名的投行，后来才慢慢知道它们其实根本不招人，或者名额极少。通过修改简历，分析自我等准备工作，慢慢也更了解自己的兴趣所在和优势所在。被诸多投行拒掉，心里也不着急。</p>
<p>校园招聘我走的不是很积极。因为招聘的旺季，我还在SAS中国研发中心，保持着几乎全职的实习状态，所以SAS也成了我找工作的一个标杆。我的观察是，比SAS好的公司，大概也不多；跟它一样好，但更适合我的，就更少了。</p>
<p>之前也跟猎头接触过。第一次比较搞笑，一个女声打电话过来，拨的是我办公室的电话，报了一个英文名，说是北京的一家猎头公司。先问我是不是SAS中国研发中心，我说是，接着她说要为微软的一个数据库项目招人。我说现在不方便，她就要了我的手机号，说下次再联系。因为第一次接到猎头的电话，心里难免有些激动。中午吃饭时跟几个要好的同事提到这事，原来他们也都接到这个的电话，唉，这就没什么好谈的了。我们想下次其他组的同事也要陆续接到这个电话，于是一起打趣，这猎头，大概是拿着我们的名单，一个个打过去的。</p>
<p>这次猎头跟我联系，我知道它是一家知名的医药公司，赛诺菲巴斯德(Sanofi Pasteur)，总部法国，是世界上最大的疫苗公司。以前一些CRO跟我联系，我都不是很感兴趣。现在却是一家药厂自己的研发中心需要SAS Programmer（又叫Statistical Programmer）,这让我有些心动。在SAS中国研发中心，除了SAS语言，我接触更多的是SAS的各种产品和解决方案，都是在类似实验室的环境里运用。学SAS这么久，也想把它运用在某个行业里面。我回复猎头公司，说我愿意跟潜在的东家谈一谈。</p>
<p>当时把简历寄过去后，我就回老家过年去了。跟公司的接触，也饶有趣味。在家里，就收到现在老板的一个电话，先用中文说明来意，再简单聊一下，然后问我可不可以用英文聊聊。当时也只好硬着头皮说了，——这个真是非常的不适应，在老家，我连说普通话都不自在，更不用说是英语了，让父母听着别扭。这次电面后，约好年后回北京再面谈。</p>
<p>公司在国贸。年后我过去，进老板的办公室，笑着点头去握手，老板却先来一句nice to meet you。我暗想惨了，一上来就英语啊。我是准备了英语面试，心里却是还想要些缓冲。老板在美国念的博士，在国外工作数十年，这次回国是来负责筹建北京的研发中心。这次全英文面试，也说是随便聊聊，大概持续了一个小时。虽然我英语不是很好，但英文面试，倒是不惧，以前也真刀真枪面对过数回，从俄克拉何马的英语到印度的英语，当然还有中国的英语，屡战屡败屡败屡战这么一路过来，当然丝毫不怕。面试结束，老板笑着说了句我的英语真是不咋地。听了这句，我心里倒舒坦起来，觉得有了被认同的感觉。果然，老板给我留了个名片，约好下次再联系。——说到名片，我在学校做社团时就准备了些。在一些有业内人士出没的技术交流活动里，我是顽强地递过不少名片，给自己争取了些工作机会。</p>
<p>说口语，我觉得对我们技术背景的朋友来说，准备多少都不为过。在实习工作中，每天阅读很多技术文档，还有发邮件，英文阅读和写作问题都不大，但口语实践的机会不多——大多数外企，其实也多是中国人扎堆。我觉得自己口语的突破，不是来自外教，也不是自己私下里在大声背些范文，而是以前几次越洋的电话面试，让我实在躲不开，硬着头皮说上几小时。这坎一旦跨过去，以后就都轻松了，遗憾的是口音还没有跟着有显著提升。接下来公司给我安排了一次电面，面试官是美国那边的programming head和statistics head。那次是晚上十一二点，口语再烂，聊的都是我熟悉的话题，蜿蜒曲折也能沟通下去。</p>
<p>提到面试，我比较幸运，因为面试过程中，需要我说的，都是我所熟悉的和我感兴趣的，关于我的学术背景，以及工作本身需要的技能。作为一个求职者，我知道，这能给我提供一个真正平等的智力环境。</p>
<p>这么几番接触，公司唯一放心不下的，是我背景这么复杂（经济、金融、软件），兴趣又这么广泛，我如何能够保持恰当的commitment?</p>
<p>这时我心里，其实也很多激荡。又到了考虑自己的背景和兴趣的时候，——可能又是要默念《未走过的路》了。我的兴趣和背景，要留在IT业，也不赖。转去医药公司，这对我来说又是一个全新的行业，里面只有SAS编程是我熟悉的。除了想提高自己的SAS应用水平，当时还有几个因素，影响着我的决策。我是要加入一个新开设的研发中心，感觉机会会多一些，以后如果能够承担更多的责任，我的经管背景，或许还能用得上。另外，在与公司的来回接触中，感觉它非常人性化，自己在各个流程都受到了极大的尊重，这与校园招聘中被赶鸭子一般赶来赶去的感觉完全不一样。</p>
<p>我跟老板说，我会珍惜自己的职业前程。如果我加入一家公司，进入一个行业，不会随便跳出，知道那样会损害自己在业内的声誉。老板说大伙都是聪明人，那公司也就没有什么疑虑了。</p>
<p>关于找工作。我给原东家挑过简历，在公司也参与过面试几个候选人，对师弟师妹要讲的是，找工作，不妨站在雇主的立场上考虑些问题，然后反观自己的准备。要知道，公司招人是要花成本的，你是你这个职位所要求的技术领域的专家，你可以想象，雇主需要什么样的人，以及用什么样的方式合适展现出来。比如，写简历时，就该多想着HR或部门会如何看待自己的简历和措辞。</p>
<p>我有很多朋友，像刘未鹏、谢益辉，都非常积极维护自己的技术博客，这种展示最为从容。我看这是最有效的自我营销的方式之一，潜在的雇主可能很早就能够了解你，而且HR、猎头也都会积极去网络上收罗候选人。除了博客，在专业社交网站如LinkedIn等推销自己，也能够建立自己在劳动市场上的良好声誉。</p>
<p>在学术圈子，每一个博士候选人都会积极参加各种专业会议，以期与潜在的东家尽早建立联系。这个思路，放在大学生找工作方面，也是非常有效，特别是我们的IT领域。可以通过论坛讨论、技术会议等各种渠道，积极接触你感兴趣的行业、公司和人。这个应该不难，都2.0了，我们可以通过博客、社交网站、Twitter以及老师朋友推荐认识你感兴趣的业界人士。跟这个行业的人接触了，以后跟雇潜在雇主打交道时就能更有自信。</p>
<p><strong>后记</strong></p>
<p>老罗说彪悍的人生不需要解释。在我求学的这些年，每一个重要阶段，我都要向朋友们解释一遍我正在做什么。进大学，我向很多高中朋友说我去念经济学了，读研后我对大学同学说我修的是软件工程，现在快毕业了，我要对我那群进软件公司的同学说，我去药厂了。以前听孟岩讲过，你做什么，而不是你想什么，决定你要成为什么样的人。我进入一个新的领域，这或将成为我人生诸多折腾的一个了结，我的时间，我的精力，都花在这里，我以后的骄傲也会在这里。</p>
<p>2009-6-27，二稿</p>
<p>推荐网址：</p>
<p>SAS</p>
<p>1. SAS-L(SAS全球用户最活跃的电子邮件组，英文，推荐用Gmail订阅) <a href="https://groups.google.com/group/comp.soft-sys.sas/" rel='nofollow'>https://groups.google.com/group/comp.soft-sys.sas/</a></p>
<p>2. SAS用户与爱好者俱乐部（SAS中国用户组，由SAS中国公司赞助）<a href="http://www.sas.com/offices/asiapacific/china/events/2008/2008q3/20080917.htm" rel='nofollow'>http://www.sas.com/offices/asiapacific/china/events/2008/2008q3/20080917.htm</a></p>
<p>以下是两个活跃的SAS中文论坛：</p>
<p>3. SAS中文论坛，<a href="http://www.mysas.net/forum/" rel='nofollow'>http://www.mysas.net/forum/</a></p>
<p>4. SASor,<a href="http://sasor.feoh.net/" rel='nofollow'>http://sasor.feoh.net/</a></p>
<p>统计学、商务智能</p>
<p>5. 统计之都（应用统计学、数据挖掘，群体博客），<a href="http://cos.name/" rel='nofollow'>http://cos.name/</a></p>
<p>6. TTNN BI观点（商务智能电子邮件组，中文），<a href="https://groups.google.com/group/ttnn" rel='nofollow'>https://groups.google.com/group/ttnn</a></p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/04/think-sas-1/" title="Think SAS(一)">Think SAS(一)</a> (92)</li><li><a href="http://cos.name/2010/09/3rd-bbf/" title="北京数据管理与生物统计论坛（BBF）第三次聚会见闻录">北京数据管理与生物统计论坛（BBF）第三次聚会见闻录</a> (6)</li><li><a href="http://cos.name/2009/02/measure-classification-model-performance-lift-gain/" title="分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(3): Lift和Gain">分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(3): Lift和Gain</a> (7)</li><li><a href="http://cos.name/2008/12/measure-classification-model-performance-roc-auc/" title="分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(2): ROC和AUC">分类模型的性能评估&mdash;&mdash;以SAS Logistic回归为例(2): ROC和AUC</a> (11)</li><li><a href="http://cos.name/2008/12/measure-classification-model-performance-confusion-matrix/" title="分类模型的性能评估——以SAS Logistic回归为例(1): 混淆矩阵">分类模型的性能评估——以SAS Logistic回归为例(1): 混淆矩阵</a> (16)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >Yazhong</a> : <a class="comment_content" href="http://cos.name/2009/08/econ-software-sas/#comment-1610" title="View the entire comment by Yazhong" >真的很不错，SAS程序员在医药研发中大有作为，前景不错。
我来自CRO Covance, 几年我们...</a></li>
<li><a class="commentor" href="" >wurui</a> : <a class="comment_content" href="http://cos.name/2009/08/econ-software-sas/#comment-1278" title="View the entire comment by wurui" >看着一位位老乡如此本事，作为同龄人倍感压力啊，努力，咱这phd也不能读得浑浑噩噩~</a></li>
<li><a class="commentor" href="" >盟</a> : <a class="comment_content" href="http://cos.name/2009/08/econ-software-sas/#comment-1221" title="View the entire comment by 盟" >thank u really for these encouraging words</a></li>
<li><a class="commentor" href="" >盟</a> : <a class="comment_content" href="http://cos.name/2009/08/econ-software-sas/#comment-1220" title="View the entire comment by 盟" >tough world, tough guy</a></li>
<li><a class="commentor" href="" >song</a> : <a class="comment_content" href="http://cos.name/2009/08/econ-software-sas/#comment-1207" title="View the entire comment by song" >我目前是学数学与应用数学的本科生，打算往考经济统计方面研究生。拜读了你的文章，收益匪浅~谢谢分享。</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/08/econ-software-sas/feed/</wfw:commentRss>
		<slash:comments>31</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>R中面向对象编程方法</title>
		<link>http://cos.name/2009/07/studying-notes-on-oop-in-r/</link>
		<comments>http://cos.name/2009/07/studying-notes-on-oop-in-r/#comments</comments>
		<pubDate>Sat, 04 Jul 2009 03:13:09 +0000</pubDate>
		<dc:creator>胡荣兴</dc:creator>
				<category><![CDATA[统计软件]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[S4]]></category>
		<category><![CDATA[面向对象]]></category>

		<guid isPermaLink="false">http://cos.name/?p=1376</guid>
		<description><![CDATA[R主要面向统计计算，似乎很少会用到面向对象的编程方法。但在统计计算中，在下列情形中使用面向对象的编程方法可以编程更有效率。 1）当需要用一种新的方式来表示数据，该方式与已有的数据类型有区别的时候。 2）当需要一个新的函数，该函数可以根据不同的参数类型做出不同的反应的时候。 在R中，经常需要定义一个新的函数，并且定义一个新的函数也是一项繁重的工作。相反，较少去定义一个新的类。但有时候定义一个类是一个很关键的步骤。一个类通常决定了如何对对象进行处理，决定了对象中应当包含什么样的信息。甚至有时候，类的定义决定你的项目的成败。(本文的PDF版本:R中的面象对象编程学习笔记) 1. 旧的实现方法 R的面向对象(OOP)是基于泛型函数(generic function)的，而不是基于类层次结构。什么是R中的泛型函数？R中的面向对象是怎么样的呢？我们首先看下面来自使用R编写统计程序,第3部分:可重用和面向对象中的一个实例。 下面我们首先来创建一个泛型函数whoAmI( ) # 创建泛型函数 &#62; whoAmI &#60;- function(x, ...) UseMethod("whoAmI") &#62; whoAmI.foo &#60;- function(x) print("I am a foo") &#62; whoAmI.bar &#60;- function(x) print("I am a bar") &#62; whoAmI.default &#60;- function(x) print("I don't know who I am") 在R中，每个对象都属于0个或1个或多个类，我们可以用class( )函数查看对象所属的类。 &#62; a = 1:10 &#62; b = 2:20 &#62; [...]]]></description>
			<content:encoded><![CDATA[<p>R主要面向统计计算，似乎很少会用到面向对象的编程方法。但在统计计算中，在下列情形中使用面向对象的编程方法可以编程更有效率。<br />
1）当需要用一种新的方式来表示数据，该方式与已有的数据类型有区别的时候。<br />
2）当需要一个新的函数，该函数可以根据不同的参数类型做出不同的反应的时候。<br />
在R中，经常需要定义一个新的函数，并且定义一个新的函数也是一项繁重的工作。相反，较少去定义一个新的类。但有时候定义一个类是一个很关键的步骤。一个类通常决定了如何对对象进行处理，决定了对象中应当包含什么样的信息。甚至有时候，类的定义决定你的项目的成败。(本文的PDF版本:<a href="http://cos.name/wp-content/uploads/2009/07/S4Method.pdf" rel='nofollow' rel='nofollow'>R中的面象对象编程学习笔记</a>)<br />
<span id="more-1376"></span></p>
<h1>1. 旧的实现方法</h1>
<p>R的<em>面向对象(OOP)</em>是基于<em>泛型函数(generic function)</em>的，而不是基于类层次结构。什么是R中的泛型函数？R中的面向对象是怎么样的呢？我们首先看下面来自<a href="http://www.ibm.com/developerworks/cn/linux/l-r3.html" rel='nofollow'>使用R编写统计程序,第3部分:可重用和面向对象</a>中的一个实例。</p>
<p>下面我们首先来创建一个泛型函数whoAmI( )</p>
<pre># 创建泛型函数
&gt; whoAmI &lt;- function(x, ...) UseMethod("whoAmI")
&gt; whoAmI.foo &lt;- function(x) print("I am a foo")
&gt; whoAmI.bar &lt;- function(x) print("I am a bar")
&gt; whoAmI.default &lt;- function(x) print("I don't know who I am")</pre>
<p>在R中，每个对象都属于0个或1个或多个类，我们可以用class( )函数查看对象所属的类。</p>
<pre>&gt; a = 1:10
&gt; b = 2:20
&gt; class(a)
[1] "integer"
&gt; class(b)
[1] "integer"</pre>
<p>有了泛型函数和类之后，我们就可以看到R中的面泛型函数是如何工作的</p>
<pre>&gt; whoAmI(a) # a的类为“integer”，没有为该类定义方法，
# 就执行whoAmI.default方法
[1] "I don't know who I am"
&gt; attr(a,'class') &lt;- 'foo' # 用attr( )函数将a的类指定为“foo”
&gt; class(a)
[1] "foo"
&gt; attr(b,'class')&lt;-c('baz','bam','bar') #指定b的属于三个类“baz”“bam”“bar”
&gt; class(b)
[1] "baz" "bam" "bar"
&gt; whoAmI(a) # 现在a属于“foo”类，执行whoAmI.foo( )
[1] "I am a foo"
&gt; whoAmI(b) # b虽然属于三个类，但只对“bar”类定义了
# 方法，所以就执行whoAmI.bar()
[1] "I am a bar"
&gt; attr(a,'class') &lt;- 'bar' # 改变a的类
&gt; class(a)
[1] "bar"
&gt; whoAmI(a)
[1] "I am a bar"</pre>
<p>上面的例子中提到了一个对象同时属于多个类的情况，再看下面的一个补充实例。</p>
<pre>&gt; meth1 &lt;- function(x) UseMethod("meth1")
&gt; meth1.Mom &lt;- function(x) print("Mom's meth1") # meth1对类“Mom”
&gt; meth1.Dad &lt;- function(x) print("Dad's meth1") # 和类“Dad”都定义了方法
&gt; meth2 &lt;- function(x) UseMethod("meth2") # meth2只对类
&gt; meth2.Dad &lt;- function(x) print("Dad's meth2") # “Dad”定义了方法
&gt; attr(a,'class') &lt;- c('Mom','Dad')
&gt; meth1(a) # 执行了meth1.Mom( ),因为Mom在前。
[1] "Mom's meth1"
&gt; meth2(a)
[1] "Dad's meth2"</pre>
<p>包含祖先的一个例子。</p>
<pre>#包含祖先
char0 = character(0)
makeMRO &lt;- function(classes = char0, parents = char0) {
    # Create a method resolution order from an optional
    # explicit list and an optional list of parents
    mro &lt;- c(classes)
    for (name in parents) {
        mro &lt;- c(mro, name)
        ancestors &lt;- attr(get(name), "class")
        mro &lt;- c(mro, ancestors[ancestors != name])
    }
    return(mro)
}
NewInstance &lt;- function(value = 0, classes = char0,
    parents = char0) {
    # Create a new object based on initial value,
    # explicit classes and parents (all optional)
    obj &lt;- value
    attr(obj, "class") &lt;- makeMRO(classes, parents)
    return(obj)
}
MaternalGrandma &lt;- NewInstance()
PaternalGrandma &lt;- NewInstance()
Mom &lt;- NewInstance(classes = "Mom", parents = "MaternalGrandma")
Dad &lt;- NewInstance(0, classes = c("Dad", "Uncle"),
    "PaternalGrandma")
Me &lt;- NewInstance(value = "Hello World", "Me", c("Mom",
    "Dad"))
&gt; print(Me)
[1] "Hello World"
attr(,"class")
[1] "Me" "Mom" "MaternalGrandma" "Dad"
[5] "Uncle" "PaternalGrandma"</pre>
<p>从上面的例子，我们可以看到，R中的“面向对象”是以类和泛型函数为基础，类可以多重继承类，泛型函数可以分派到任意的参数（签名,signature）集合，泛型函数将不同的方法聚集到一起，由R根据函数的对象的类型来决定选择执行哪个方法。在某些情况下，类和方法是不同的概念，我样要区别对待。</p>
<h1>2.类</h1>
<p>用setClass来定义一个类。</p>
<p>setClass(Class, representation, prototype, contains=character(),</p>
<p>validity, access, where=1, version=FALSE)</p>
<p>其中：</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="177" valign="top">Class</td>
<td width="391" valign="top">字符串，类的名称</td>
</tr>
<tr>
<td width="177" valign="top">representation</td>
<td width="391" valign="top">新的类的接口，或者该类扩展的其它类。通常是对representation函数的一个调用。</td>
</tr>
<tr>
<td width="177" valign="top">prototype</td>
<td width="391" valign="top">为接口提供的默认的数据对象。如果在构造一个新的类的时候，不明确地改写，那么新的实例将采用这些数据。</td>
</tr>
<tr>
<td width="177" valign="top">contains</td>
<td width="391" valign="top">该类所扩展的类，所有扩展的类的新的实例都会继承其所有父类的接口</td>
</tr>
<tr>
<td width="177" valign="top">validity, access, version</td>
<td width="391" valign="top">与S-Plus兼容的控制参数</td>
</tr>
<tr>
<td width="177" valign="top">where</td>
<td width="391" valign="top">存储或移除定义的元数据的环境</td>
</tr>
</tbody>
</table>
<p>定义了一个类后，就可以用函数new()来生成一个类的实例(instances)。类定义了一个对象的结构。类的实例代表了对象本身。一个子类是对其父类的扩展，一个新的类将包含其父类的所有接口。在创建一个新的类时，接口的名字不能重复（包括其直接或间接的父类）。下面的代码将创建两个类foo和bar，再创建它们的一个子类baz。</p>
<pre>&gt; library(methods)
&gt; setClass("foo",representation(a="character",b="numeric"))
[1] "foo"
&gt; setClass("bar", representation(d = "numeric", c = "numeric"))
[1] "bar"
&gt; setClass("baz", contains = c("foo", "bar"))
[1] "baz"
&gt; getClass("baz")
Class "baz" [in ".GlobalEnv"]
Slots:
Name: a b d c
Class: character numeric numeric numeric
Extends: "foo", "bar"</pre>
<p>现在我们可以生成类baz的一个实例。</p>
<pre>&gt; x &lt;- new("baz", a = "xxx", b = 5, c = 10)
&gt; x
An object of class "baz"
Slot "a":
[1] "xxx"
Slot "b":
[1] 5
Slot "d":
numeric(0)
Slot "c":
[1] 10</pre>
<p>可以通过操作符@访问接口中的数据。但最好的办法是不直接访问接口的数据，而是定义一些特殊的方法来访问这些数据。</p>
<pre>&gt; x@a
[1] "xxx"</pre>
<h1>3. 虚类</h1>
<p>虚类就是不会用来生成实例的类。它们是用来将拥有不同的representations的类（它们不能互相继承）链接起来, 可以通过虚类为这些不同的representations提供相似的功能。一个标准的做法就是建立一个虚类，然后用其它类来扩展它。</p>
<p>在实际中，可以通过以下几种不同的方式来使用该虚类。</p>
<p>1. 虚类的方法将用到其所有的扩展类中。</p>
<p>2. 新的类的接口将与虚类的接口的数据类型一致，这样可以使接口的多样化。</p>
<p>3. 虚类的接口将会出现在它的所有扩展类中。</p>
<p>下面我们用类来表示，一个树状图。一个树状图的结点有三个值：高度、左结点、右结点。终端结点与之不同，有一个高度和一个值（也有可能是另一个对象的实例。）我们可以用一个虚类dendNode来表示该结构。我们可以再定义两个该类的扩展类：终端和非终端结点。</p>
<pre>&gt; setClass("dendNode")
[1] "dendNode"
&gt; setClass("dnode", representation(left = "dendNode", right = "dendNode",
+ height = "numeric"), contains = "dendNode")
[1] "dnode"
&gt; setClass("tnode", representation(height = "numeric", value = "numeric",
+ label = "character"), contains = "dendNode")
[1] "tnode"</pre>
<p>现在我们就可以创建树了，它的结点或者是终端结点或者是非终端节点。在类dnode中，它的左节点和右节点都是dendNode类的实例，而dnode类本身又是dendNode的扩展。在此例中虚类被用来允许两个不同的类：左节点和右节点。这种设计使得可以重复使用树变得简单。</p>
<p>在实际中，我们经常会出现这样的问题，希望一个接口或者是一个列表或者是一个空对象（NULL( )）。因为一个NULL( )本身不是一个列表，所以它们不能共享同一个接口。我们可以创建一个虚拟类来扩展列表类和NULL( )类。</p>
<p>有两种方法可以建立虚类。第一种方法，与上面一样，用setClass( )建立一个没有representation的类。第二种方法，在参数representation中包括类“VIRTUAL”</p>
<pre>&gt; setClass("myVclass", representation(a = "character", "VIRTUAL"))
[1] "myVclass"
&gt; getClass("myVclass")
Virtual Class "myVclass" [in ".GlobalEnv"]
Slots:
Name: a
Class: character</pre>
<h1>4. 初始化和原型</h1>
<p>有两种办法可以用来控制类的实例生成的对象的初始值。</p>
<p>第一种方法：可以用参数prototype来控制生成的实例的值。使用该参数，可以将任何接口赋初值。</p>
<pre>&gt; setClass("xx", representation(a = "numeric", b = "character"),
+ prototype(a = 3, b = "hi there"))
[1] "xx"
&gt; new("xx")
An object of class "xx"
Slot "a":
[1] 3
Slot "b":
[1] "hi there"</pre>
<p>第二种方法是为该类指定一个initialize方法，用该方法为类的实例赋值。</p>
<pre>&gt; setMethod("initialize", "xx", function(.Object, b)
+ {
+ .Object@b &lt;- b
+ .Object@a &lt;- nchar(b)
+ .Object
+ })
[1] "initialize"
&gt; new("xx", b = "yowser")
An object of class "xx"
Slot "a":
[1] 6
Slot "b":
[1] "yowser"</pre>
<p>注意在第二种方法中，应当在initialize方法中返回该对象。</p>
<h1>5. 泛型函数和方法</h1>
<p>面向对象编程的一个重要方面就是泛型函数。泛型函数实际上就是一个分派机制。方法就是一种特殊的函数，它能根据特定的输入对象执行需要执行的任务。泛型函数的工作就是针对不同的输入参数决定什么样的方法被执行。一旦对泛型函数进行了签名，那么泛型函数就不能添加新的参数了。在设计泛型函数的参数时，要将可能用到的参数都包括进来。</p>
<h1>6. 访问子函数</h1>
<p>我们可以通过@运算符来访问接口，但在实际编程中并不建议这么做。我样可以通过访问子函数来访问接口。</p>
<pre>&gt; setClass("foo", representation(a = "ANY")) #新建一个类foo
[1] "foo"
#申明一个标准的泛型函数a
&gt; if (!isGeneric("a")) {
    if (is.function("a"))
        fun &lt;- a
    else fun &lt;- function(object) standardGeneric("a")
    setGeneric("a", fun)
}
&gt; setMethod("a", "foo", function(object) object@a)
[1] "a"
&gt; b &lt;- new("foo", a = 10)
&gt; a(b)
[1] 10</pre>
<p>R主要面向统计计算，似乎很少会用到面向对象的编程方法。但在统计计算中，在下列情形中使用面向对象的编程方法可以编程更有效率。</p>
<p>1）当需要用一种新的方式来表示数据，该方式与已有的数据类型有区别的时候。</p>
<p>2）当需要一个新的函数，该函数可以根据不同的参数类型做出不同的反应的时候。</p>
<p>在R中，经常需要定义一个新的函数，并且定义一个新的函数也是一项繁重的工作。相反，较少去定义一个新的类。但有时候定义一个类是一个很关键的步骤。一个类通常决定了如何对对象进行处理，决定了对象中应当包含什么样的信息。甚至有时候，类的定义决定你的项目的成败。</p>
<p>我们来看下面的一个例子。在该例中，我们将定义一个名为whatIs( )的函数，该函数返回对象的类型。</p>
<pre>&gt; whatIs &lt;- function(object) data.class(object)
&gt; whatIs(1:10)
[1] "numeric"
&gt; whatIs(matrix())
[1] "matrix"
&gt; whatIs(whatIs)
[1] "function"</pre>
<p>上面的程序好像太简单，我们还可以打印出对象的长度。</p>
<pre>&gt; whatIs &lt;- function(object) cat("类：",
+ data.class(object),"\n长度：",length(object),"\n")
&gt; whatIs(1:10)
类： numeric
长度： 10
&gt; whatIs(matrix())
类： matrix
长度： 1
&gt; whatIs(whatIs)
类： function
长度： 1
&gt; A&lt;-matrix(1:6,c(2,3))
&gt; A
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
&gt; whatIs(A)
类： matrix
长度： 6</pre>
<p>现在看来，又改进了一步，但是还是有点不尽如人意的地方，这里给出了函数的长度，意义不大。对于矩阵，我们更想知道它的行数和列数。所以我们需要为function类和matrix类单独定义函数，才能得到我们期望的信息：</p>
<pre>&gt; whatIs.function &lt;- function(object) cat("类：",
+ data.class(object),"\n")
&gt; whatIs.function(whatIs)
类： function
&gt; whatIs.matrix &lt;- function(object) cat("类：",
+ data.class(object),"\n",nrow(object),"行",ncol(object),"列\n")
&gt; whatIs.matrix(A)
类： matrix
2 行 3 列</pre>
<h1>7. 定义方法</h1>
<p>在上面的例子中，为了得到我们想要的信息，我们定义了三个功能类似的函数，这样程序比较散乱，使用起来也比较繁琐。我们希望通过一个统一的函数名whatIs( )来代表上述三个函数，然后根据输入的参数的类型(function, matrix或其它)来决定使用哪一个函数(whatIs.function( ), whatIs.function( )或whatIs( ) )。要完成该工作，我们可以使用函数setMethod( )。</p>
<pre>&gt; setMethod("whatIs","function", whatIs.function)
用函数"whatIs"来建立新的同屬函数
[1] "whatIs"
&gt; setMethod("whatIs","matrix", whatIs.matrix)
[1] "whatIs"
&gt; whatIs(1:10)
类： numeric
长度： 10
&gt; whatIs(whatIs)
类： standardGeneric
&gt; whatIs(A)
类： matrix
2 行 3 列</pre>
<p>现在我们看到，我们只用一个函数whatIs( )就可以根据参数的类型执行不同的程序代码。这里的函数whatIs( )我们称之为泛型函数（上面的输出显示为“standardGeneric”），分别针对不同类型的对象的三个不同的程序功能称为方法（method）。</p>
<p>setMethod( )函数的三个参数分别告诉setMethod对什么泛型函数指定方法，执行该方法对应的参数的类型，执行的方法。其中第二项称为签名（signature）。</p>
<p>showMethods( ) 查看为函数函数定义了哪些方法。</p>
<p>dumpMethod( ) 提取为泛型函数的某个方法。</p>
<h4><a name="_附录1_R中的基本类"></a>附录: R中的基本类</h4>
<pre>### The following are all basic vector classes.
### They can appear as class names in method signatures,
### in calls to as(), is(), and new().
"character"
"complex"
"double"
"expression"
"integer"
"list"
"logical"
"numeric"
"single"
"raw"
### the class
"vector"
### is a virtual class, extended by all the above
### The following are additional basic classes
"NULL" # NULL objects
"function" # function objects, including primitives
"externalptr" # raw external pointers for use in C code
"ANY" # virtual classes used by the methods package itself
"VIRTUAL"
"missing"
## The following class names can appear in method signatures,
## as the class in as() and is() expressions, and, except for
## the classes commented as VIRTUAL, in calls to new()
"matrix"
"array"
"ts"
"structure" ## VIRTUAL
The specific classes all extend class "structure", directly, and class "vector", by class "structure".</pre>
<p>（由于不习惯在网站上编辑，更多内容请查看：<a href="http://cos.name/wp-content/uploads/2009/07/S4Method.pdf" rel='nofollow' rel='nofollow'>R中的面象对象编程学习笔记</a>)</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2010/04/think-sas-1/" title="Think SAS(一)">Think SAS(一)</a> (92)</li><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/11/a-tutorial-on-package-actuar-1/" title="用R也能做精算—actuar包学习笔记（一）">用R也能做精算—actuar包学习笔记（一）</a> (12)</li><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/07/drawing-china-map-using-r/" title="用R软件绘制中国分省市地图">用R软件绘制中国分省市地图</a> (47)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >zhangwx</a> : <a class="comment_content" href="http://cos.name/2009/07/studying-notes-on-oop-in-r/#comment-863" title="View the entire comment by zhangwx" >非常感谢！平时工作忙，回复的时间比较晚。</a></li>
<li><a class="commentor" href="http://www.yihui.name" >谢益辉</a> : <a class="comment_content" href="http://cos.name/2009/07/studying-notes-on-oop-in-r/#comment-833" title="View the entire comment by 谢益辉" >你用R分析一下R的源代码就知道了，R主要是用R写的（这句话看起来很崩溃？），加上一部分C语言，外加少...</a></li>
<li><a class="commentor" href="" >zhangwx</a> : <a class="comment_content" href="http://cos.name/2009/07/studying-notes-on-oop-in-r/#comment-831" title="View the entire comment by zhangwx" >请问R的底层是用什么语言写的？
C++吗
？</a></li>
<li><a class="commentor" href="http://hi.baidu.com/luansheng1229" >栾生</a> : <a class="comment_content" href="http://cos.name/2009/07/studying-notes-on-oop-in-r/#comment-760" title="View the entire comment by 栾生" >太棒了，这正是我需要的。还有上一篇的制作地图，也很爽。都是好文章啊！</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2009/07/studying-notes-on-oop-in-r/#comment-747" title="View the entire comment by 邱怡轩" >之前确实没有注意过这些，学习了！</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/07/studying-notes-on-oop-in-r/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>用R软件绘制中国分省市地图</title>
		<link>http://cos.name/2009/07/drawing-china-map-using-r/</link>
		<comments>http://cos.name/2009/07/drawing-china-map-using-r/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 05:25:03 +0000</pubDate>
		<dc:creator>邱怡轩</dc:creator>
				<category><![CDATA[推荐文章]]></category>
		<category><![CDATA[统计之都]]></category>
		<category><![CDATA[统计软件]]></category>
		<category><![CDATA[GIS数据]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[R软件]]></category>
		<category><![CDATA[中国地图]]></category>

		<guid isPermaLink="false">http://cos.name/?p=1335</guid>
		<description><![CDATA[鉴于最近有不少人在讨论用R软件绘制地图的问题，我也就跟着凑了凑热闹，对相应的方法学习了一番。下面的这篇文章是一个初步的介绍，还有很多内容仍在学习和探索中，如果大家有什么意见或建议，我将根据自己学习的情况对文章进行进一步的补充。]]></description>
			<content:encoded><![CDATA[<p><span style="color: #ff0000;">【注】新版本的<code>maptools</code>包对很多函数进行了修改，对于修改的内容，文章中用红色的文字进行了说明。</span></p>
<p>鉴于最近有不少人在讨论用R软件绘制地图的问题，我也就跟着凑了凑热闹，对相应的方法学习了一番。下面的这篇文章是一个初步的介绍，还有很多内容仍在学习和探索中，如果大家有什么意见或建议，我将根据自己学习的情况对文章进行进一步的补充。</p>
<p>在R中绘制地图其实是十分方便的，最直接的办法大概就是安装<code>maps</code>和<code>mapdata</code>这两个包，然后输入下面的命令：</p>
<pre>library(maps)
library(mapdata)
map("china")</pre>
<p>其中<code>map()</code>函数还可以加上很多参数，在这里就不一一详述，具体的用法只需问号之。然而仔细看一看这张地图你会发现重庆市和四川省仍然是浑然一体，可见该地图的数据应该是有些年头了。<span id="more-1335"></span></p>
<p>幸运的是，通过<a title="终于搞定了中国分省市地图" href="http://yihui.name/cn/2007/09/china-map-at-province-level/" rel='nofollow'>谢益辉的这篇博文</a>我们已经可以大体知道该如何操作了，下面就为大家介绍一下具体的步骤。</p>
<p>首先，从<a href="http://cos.name/wp-content/uploads/2009/07/chinaprovinceborderdata_tar_gz.zip" rel='nofollow'>这里</a>下载中国地图的GIS数据，这是一个压缩包，完全解压后包含三个文件（bou2_4p.dbf、bou2_4p.shp和bou2_4p.shx），将这三个文件解压到同一个目录下，并在R中设好相应的工作空间，然后安装<code>maptools</code>包，运行如下程序：</p>
<pre>library(maptools);
x=read.shape('bou2_4p.shp');#下文中会继续用到x这个变量，
                            #如果你用的是其它的名称，
                            #请在下文的程序中也进行相应的改动。
plot(x);</pre>
<p><span style="color: #ff0000;">【修改】新版本的maptools包不再提供read.shape()函数，请用readShapePoly()代替。</span></p>
<p>这时一张完整的中国地图就已经画好了。但是在实际使用的过程中，我们往往会根据自己的需要对地图中的某些省份着以特定的颜色，这时就可以通过调节<code>plot</code>命令中的<code>fg</code>参数来予以实现。然而为了清楚地说明这部分的内容，我需要插播一段R绘制地图的原理。</p>
<p style="text-align: center;">======================传说中的分割线=====================</p>
<p>在绘制地图时，每一个省市自治区或者岛屿都是用一个多边形来表示的。之前的GIS数据，其实就是提供了每一个行政区其多边形逐点的坐标，然后R软件通过顺次连接这些坐标，就绘制出了一个多边形区域。在上面的数据中，一共包含了925个多边形的信息，之所以有这么多是因为一些省份有很多小的附属岛屿。在这925个多边形中，每一个都对应一个唯一的ID，编号分别从1到925。</p>
<p style="text-align: center;">======================传说中的分割线=====================</p>
<p>回到刚才的话题，<code>plot</code>命令中的<code>fg</code>参数在本例中应该是一个长度为925的向量，其第i个分量的取值就代表了地图中第i个多边形的颜色。一个简单的尝试是运行下面这个命令看看效果：</p>
<pre>plot(x,fg=gray(924:0/924));</pre>
<p><span style="color: #ff0000;">【修改】新版本的<code>maptools</code>包的绘图参数也有所改变，请将<code>fg</code>换成<code>col</code>。</span></p>
<p>于是自然就产生了一个问题：如何获取某一个特定地区的ID，进而设置我们想要的颜色？事实上，在变量x中，就已经存储了我们想要的信息。在R中输入“<code>x[[2]]</code>”或“<code>x$att.data</code>”，会得到一个925行7列的数据框，这其实是bou2_4p.dbf这个文件中存储的信息，之前的<code>read.shape()</code>函数虽然读取的是bou2_4p.shp文件，但在默认情况下会把dbf文件的信息也放到变量之中。对于这个数据框，其行名就是每一个区域的ID编号，第一列和第二列分别是面积和周长，最后一列是该区域所属的行政区名，其它的列应该也是一些编号性质的变量。于是，通过查找相应的行政区对应的行名，就可以对<code>fg</code>参数进行赋值了。下面是我编的一个函数，用来生成所需的<code>fg</code>向量：</p>
<pre>getColor=function(mapdata,provname,provcol,othercol)
{
	f=function(x,y) ifelse(x %in% y,which(y==x),0);
	colIndex=sapply(mapdata$att.data$NAME,f,provname);
	fg=c(othercol,provcol)[colIndex+1];
	return(fg);
}</pre>
<p><span style="color: #ff0000;">【修改】地图数据的组织形式有所变化，上面函数中的<code>mapdata$att.data$NAME</code>需要替换为<code>mapdata@data$NAME</code>。</span></p>
<p>其中<code>mapdata</code>是存放地图数据的变量，在上面的例子中就是x，<code>provname</code>是需要改变颜色的地区的名称，<code>provcol</code>是对应于<code>provname</code>的代表颜色的向量（名称和数字均可），<code>othercol</code>是其它地区的颜色。举例如下：</p>
<pre>provname=c("北京市","天津市","上海市","重庆市");
provcol=c("red","green","yellow","purple");
plot(x,fg=getColor(x,provname,provcol,"white"));</pre>
<p><img class="aligncenter size-large wp-image-1366" title="map00" src="http://cos.name/wp-content/uploads/2009/07/map00-e1262748931991.png" alt="map00" width="470" height="497" /></p>
<p>注意<code>provname</code>一定要写地区的全称，写法可以参照下面这条命令生成的向量：</p>
<pre>as.character(na.omit(unique(x$att.data$NAME)));</pre>
<p>由此生成的向量有33个元素，少了澳门特别行政区，这是这个数据中的一块瑕疵。在<code>x$att.data</code>的第899行有一个<code>NA</code>，不知道它代表的是否就是澳门。</p>
<p>利用类似的方法就可以根据自己的需要对不同的区域进行着色，下面再举一例。从国家统计局获取2007年我国各地区的人口数据，然后根据人口的多少对各省份进行着色。程序如下：</p>
<pre>provname=c("北京市","天津市","河北省","山西省","内蒙古自治区",
		"辽宁省","吉林省","黑龙江省","上海市","江苏省",
		"浙江省","安徽省","福建省","江西省","山东省",
		"河南省","湖北省","湖南省","广东省",
		"广西壮族自治区","海南省","重庆市","四川省","贵州省",
		"云南省","西藏自治区","陕西省","甘肃省","青海省",
		"宁夏回族自治区","新疆维吾尔自治区","台湾省",
		"香港特别行政区");
pop=c(1633,1115,6943,3393,2405,4298,2730,3824,1858,7625,
		5060,6118,3581,4368,9367,9360,5699,6355,9449,
		4768,845,2816,8127,3762,4514,284,3748,2617,
		552,610,2095,2296,693);
provcol=rgb(red=1-pop/max(pop)/2,green=1-pop/max(pop)/2,blue=0);
plot(x,fg=getColor(x,provname,provcol,"white"),xlab="",ylab="");</pre>
<p style="text-align: center;"><a href="http://cos.name/wp-content/uploads/2009/07/map01.png" rel='nofollow'><img class="aligncenter size-full wp-image-1343" title="map01" src="http://cos.name/wp-content/uploads/2009/07/map01-e1262748729327.png" alt="map01" width="500" height="500" /></a></p>
<p>其中颜色越深的地方代表人口数越多，反之为人口数越少。</p>
<p>此外，在绘制地图的过程中，还有一个比较有用的参数是<code>recs</code>，它是一个由多边形ID组成的向量，表示在地图中只画出这些ID所代表的区域。利用这个参数，就可以画出某一部分的地图，例如下面的例子是我国中部六省的地图：</p>
<pre>getID=function(mapdata,provname)
{
	index=mapdata$att.data$NAME %in% provname;
	ids=rownames(mapdata$att.data[index,]);
	return(as.numeric(ids));
}
midchina=c("河南省","山西省","湖北省","安徽省","湖南省","江西省");
plot(x,recs=getID(x,midchina),fg="green",ol="white",xlab="",
		ylab="");</pre>
<p><img class="aligncenter size-large wp-image-1353" title="map02" src="http://cos.name/wp-content/uploads/2009/07/map02-e1262748890424.png" alt="map02" width="500" height="500" /><br />
上面的<code>getID()</code>是我编写的一个功能与<code>getColor()</code>类似的函数，用来返回指定省份的ID。</p>
<p><span style="color: #ff0000;">【修改】新版本的<code>maptools</code>包的绘图函数已经取消了<code>recs</code>这个参数，现在要实现这个功能，可以在颜色上把不需要的省份变成白色，其中填充色用<code>col</code>参数，边界颜色用<code>border</code>参数。例如上面的例子可以用下面的函数来实现：</span></p>
<pre>plot(x, col = getColor(x, midchina, rep("green", 6),
    "white"), border = "white", xlab = "", ylab = "")</pre>
<p>最后要说的是，在画出的图上仍然可以用<code>points()</code>函数和<code>text()</code>函数加上点和文字，而<code>maptools</code>包中还提供了一个<code>pointLabel()</code>函数，用来解决文本标签的重叠问题。这部分内容请参阅博文：<a href="http://yihui.name/cn/2008/10/china-map-and-city-locations-with-r/" rel='nofollow'>用R画中国地图并标注城市位置</a>，以及<a href="http://yihui.name/cn/2008/10/avoid-label-overlap-pointlabel-in-maptools/" rel='nofollow'>避免文本标签重叠：maptools中的pointLabel()</a>。</p>
<p>从以上的内容来看，本文所述的都是一些最基本的绘图方法，还没有对地理信息数据进行更进一步的分析。如果有机会的话，这一主题的下一篇文章将为大家介绍地图数据的组成结构，并说明如何将不同格式的地理数据整合起来，例如如何在上面的地图上绘制出我国的铁路、水系分布等内容。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li><a href="http://cos.name/2009/06/statistical-analysis-and-winbugs-part-4/" title="WinBUGS在统计分析中的应用（第四部分）">WinBUGS在统计分析中的应用（第四部分）</a> (0)</li><li><a href="http://cos.name/2010/04/think-sas-1/" title="Think SAS(一)">Think SAS(一)</a> (92)</li><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/11/a-tutorial-on-package-actuar-1/" title="用R也能做精算—actuar包学习笔记（一）">用R也能做精算—actuar包学习笔记（一）</a> (12)</li><li><a href="http://cos.name/2009/07/maximum-likelihood-estimation-in-r/" title="R中的极大似然估计">R中的极大似然估计</a> (2)</li></ul><h3>最新评论</h3><ul><li><a class="commentor" href="" >liujs606</a> : <a class="comment_content" href="http://cos.name/2009/07/drawing-china-map-using-r/#comment-1608" title="View the entire comment by liujs606" >我在加拿大放学一年，有个项目是关于加拿大北方森林物种特征时空变异的项目，需要把一些物种在加拿大地图上...</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2009/07/drawing-china-map-using-r/#comment-1607" title="View the entire comment by 邱怡轩" >你是在加拿大上学吗？</a></li>
<li><a class="commentor" href="" >liujs606</a> : <a class="comment_content" href="http://cos.name/2009/07/drawing-china-map-using-r/#comment-1606" title="View the entire comment by liujs606" >早晨睁眼就来看您的答复,非常感谢</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2009/07/drawing-china-map-using-r/#comment-1605" title="View the entire comment by 邱怡轩" >应该是被删了，但可以从地图信息中提取，你试一下下面的代码，函数会返回一个列表，其中每一个元素是一个矩...</a></li>
<li><a class="commentor" href="" >邱怡轩</a> : <a class="comment_content" href="http://cos.name/2009/07/drawing-china-map-using-r/#comment-1604" title="View the entire comment by 邱怡轩" >maptools包进行改版后，数据结构也发生了变化，原来的x[[2]]或x$att.data相当于现...</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://cos.name/2009/07/drawing-china-map-using-r/feed/</wfw:commentRss>
		<slash:comments>47</slash:comments>
		</item>
	</channel>
</rss>
