标签归档:统计图形

用交互式图形探索一个五百年前的脑洞

按惯例先跑几段火车,赶时间的请直接从下面油画处开读。我很少看电影,欠的稿子都写不完还看毛线电影,不过前段时间《大鱼海棠》的精美海报画面还是吸引了我的注意力(又是从涛妹的票圈看到的),深为赞叹现在国内的动画制作技术。然而过了几天,好像评论的风向就变了。可惜了情怀这个词,现在也成了为人不齿的陈词滥调了:情怀,情你个锤子的怀,你才情怀,你全家都情怀。遥想当年,萌主(周扬)在明德楼地下咖啡厅的小房间里给我们展示 R/ECharts/Shiny 的时候,第一次提到情怀一词,小板凳上的我们都感受到了内心的一团火。“厉害啊!”萌主洋洋自得。

据说《大鱼海棠》可惜在用了辣么精良的画面,却愣是没讲好一个故事(重申一遍:我没看,只是据说);相比之下,人家徐克老爷子二十年前用简陋的技术却做出动画片《小倩》,同样是用中国传统故事素材,但比《大鱼海棠》不知道高到哪里去了。

“要来找我哦,我家就在北村,门口有棵好大好大的桃花树,记得一定要来找我哦!”

那我们就来谈谈讲故事的事。在统计之都十周年感言中我曾经提到过“精致的脑洞”,今天我就给大家解说一个五百年前的脑洞,这个脑洞是我压箱底的货,一般人我不告诉他,我第一次讲它是在我的博士论文答辩会上,后来便很少提它了。讲这个洞有两个目的,一是谈谈我对讲故事本身的一些想法(讲故事本不是我擅长的,但这个洞很适合讲故事),二是演示一下交互式图形的基本概念。 继续阅读用交互式图形探索一个五百年前的脑洞

丑图百讲|好看的统计图都是相似的,难看的统计图各有各的丑

作者:水妈

大家好,我是水妈,在大学工作,主要教统计学。今天代表狗熊会,发起一个新的系列,丑图百讲。这个系列不讲炫酷的、高大上的统计图,而是给大家分享如何画好最基础的统计图

读者可能会问,为什么要分享统计画图?熊大说了,数据分析的第一步,是梳理业务目标,接下来才是分析数据。水妈认为,在分析数据环节,第一步是做描述分析。这里的描述分析,包括三个内容:一、明确行业背景和变量含义;二、用统计图、统计表以及各种统计指标对数据进行描述;三、适当的解读描述的结果,发现问题,支撑后续的建模。其中,第二个环节尤为重要,因为统计图是最容易给人留下深刻印象的。做好了,能给你的报告或者展示加分,帮助你发现数据当中的问题。做不好,那就是一场灾难。

读者可能又要问,最基础的统计图有什么好讲的啊。我看过太多学生的报告,学生看自己画的图,就像是看自己家孩子,越看越喜欢,殊不知别人早就受不了你在朋友圈天天晒娃娃了。大家不要觉得画最最基础的统计图这件事情非常简单容易,可谓不画不知道,一画吓一跳。真的自己动手去画,才知道自己画出来的图有多丑。 继续阅读丑图百讲|好看的统计图都是相似的,难看的统计图各有各的丑

Hadley Wickham:一个改变了R的人

【COS编辑部按】本译文得到了原英文作者的授权同意,翻译:冯俊晨、王小宁, 审校:邱怡轩、朱雪宁、蔡寒蕴,编辑:王小宁。

Hadley Wickham 是 RStudio 的首席科学家以及 Rice University 统计系的助理教授。他是著名图形可视化软件包 ggplot2 的开发者,以及其他许多被广泛使用的软件包的作者,代表作品如 plyrreshape2 等。本文取自PRICEONOMICS.

HadleyObama

继续阅读Hadley Wickham:一个改变了R的人

Sweave后传:统计报告中的大规模计算与缓存

学无止境。我曾以为我明白了如何在Sweave中使用缓存加快计算和图形,但后来发现我并没有真的理解,直到读了另外一些手册才明白,因此本文作为前文“Sweave:打造一个可重复的统计研究流程”之续集,向大家介绍一下如何在Sweave的计算和图形中使用缓存,以节省不必要的重复计算和作图,让那些涉及到密集型计算的用户不再对Sweave感到难堪。

如果你还没读前文,建议先从那里开始读,了解Sweave与“可重复的统计研究”的意义。简言之,Sweave是一种从代码(R代码和LaTeX)一步生成报告的工具,我们可以把整个统计分析流程融入这个工具,让我们的报告具有可重复性。然而,就普通的Sweave而言,这样做的一个明显问题就是,所有计算和作图都被融入一个文档之后,每次运行这个文档都要重复所有的计算和作图,这在很多情况下纯粹是浪费时间;比如,我只想对新添加的部分内容运行计算,而文档中的旧内容希望保持不变。这都是很合理的需求,我们需要的实际上就是一种缓存机制,将不想重复计算的对象缓存起来,需要它的时候再从缓存库中直接调出来用。

Sweave本身做不到缓存(或者很难做到),但由于R语言的扩展性以及一些疯子和天才的存在,我们可以通过R的一些附加包来完成缓存。这里的缓存有两种(不关心细节的读者可以略过):

  • 一种是对R对象的缓存,比如数据、模型(拟合好的模型)和其它计算结果等,这个缓存容易理解,我们可以把它简单想象为把计算过程中的对象存入某些特殊的缓存库(文件),下次计算的时候先查看缓存库中是否存在我们需要的对象,如果存在,那么就直接加载进来,否则就重新计算;如(伪代码):
    ## 如果存在,就加载
    if (file.exists('x.RData')) {
        load('x.RData')
    }
    ## 如果当前工作环境中不存在x,那么就重新创建它
    if (!exists('x')) {
        x = rnorm(100000)
    }

    R对象的缓存可以通过cacheSweave包(作者Roger D. Peng)实现,它真正采用的方法比上面的伪代码当然要高级(比如用代码的MD5值作数据库名等),不过用户可以不必关心这其中的细节。这种“当需要时才加载”的方式在术语上叫“延迟加载”,即Lazy Load,这在R里面也很常见,比如很多R包的数据都是采用延迟加载的方式(加载包的时候并不立刻加载数据,而是用data(name)在需要的时候加载)。

  • 另一种是图形的缓存,这是一个不可思议的魔法。cacheSweave的帮助文档和vignette中特别提到了它只能缓存R对象,无法缓存图形和其它附属输出,而开源世界的魅力就是你总能找到一些奇妙的解决方案。R包pgfSweave借力于pgf实现了图形的缓存。pgfSweave包的两位作者Cameron Bracken和Charlie Sharpsteen都是水文学相关专业出身,却在R的世界里做了这些奇妙的工作,让我觉得有点意外,这是题外话。pgf是LaTeX世界的又一项重大发明,它提供了一套全新的绘图方式(语言),而且它的图形可以通过LaTeX直接生成PDF输出(这是pgfSweave能实现缓存的关键)。关于pgf,我们可以翻一翻它726页的手册,如果你能坚持看上10分钟,感叹超过50次,那么你一定是一位超级排版爱好者。它的图形质量之高、输出之漂亮,真的是让人(至少让我)叹为观止。同样,这里我也不详细介绍细节。pgf图形的“缓存”是通过“外置化”(externalization)来实现的,简言之,pgf图形有一种输出形式如下:
    \beginpgfgraphicnamed{graph-output-1}
    \input{graph-output-1.tikz}
    \endpgfgraphicnamed
    

    如果LaTeX在运行过程中遇到这样的代码段,那么它会把tikz图形(tikz是高层实现,pgf是基础设施)先编译为PDF图形,等下次重复运行LaTeX的时候,这段代码就不必重新运行了,LaTeX会跳过它直接引入PDF图形。这样就省去了编译tikz图形的时间,同时也能得到高质量的图形输出。

    pgfSweave从R的层面上可以输出这样的代码段,并生成一个shell脚本来编译图形为PDF;而pgfSweave也会尝试根据R代码的MD5来判断一段画图的代码是否需要重复运行——如果R代码没有变化,那么图形就不必重制。这是自然而然的“缓存”。对了,pgfSweave对Sweave的图形输出作了扩展,新增了tikz输出,这是通过另一个R包tikzDevice实现的(同样两个作者),这个包可以将R图形录制为tikz绘图代码。pgfSweave依赖于cacheSweave包,把它缓存R对象的机制也引入进来,所以我们可以不必管cacheSweave,把精力放在pgfSweave上就可以了。

介绍完血腥的细节之后,我们就可以坐享高科技的便利了。下面我以一个统计计算中的经典算法“Gibbs抽样”为例来展示pgfSweave在密集型计算中的缓存功能。

Gibbs抽样的最终目的是从一个多维分布$f(X_1,X_2,\ldots,X_n)$中生成随机数,而已知的是所有的条件分布$f(X_1|X_2,\ldots,X_n)$、$f(X_2|X_1,\ldots,X_n)$、……、$f(X_n|X_1,\ldots,X_{n-1})$,并且假设我们可以很方便从这些条件分布中抽样。剩下的事情就很简单了:任意给定初始值$x_1^{(0)},x_2^{(0)},\ldots,x_n^{(0)}$,括号中的数字表示迭代次数,接下来依次迭代,随机生成$x_1^{(k)} \sim f(X_1|x_2^{(k-1)},\ldots,X_n^{(k-1)})$、$x_2^{(k)} \sim f(X_2|x_1^{(k)},\ldots,x_n^{(k-1)})$、……、$x_n^{(k)} \sim f(X_n|x_1^{(k)},\ldots,x_{n-1}^{(k)})$(迭代次数$k=1,\cdots,N$),也就是,根据上一次的迭代结果并已知条件分布的情况下,从条件分布中生成下一次的随机数(这个算法很简单,你什么时候看明白上标下标了就明白了)。这是个串行的过程,所以无法避免循环。

接下来的计算没有那么复杂,我们仅仅用一个二维正态分布为例。当我们知道一个二维正态分布的分布函数时,我们也知道它的两个边际分布都是一维正态分布,而且分布的表达式也很明确,后文我会详细提到,读者也可以参考维基百科页面。生成一维正态分布的随机数对我们来说当然是小菜一碟——直接用rnorm()就可以了。这样,我们只需要交替从$f(X|Y)$和$f(Y|X)$生成随机数,最终我们就能得到服从二维联合分布的随机数(对)。假设我们要从下面的二维正态分布生成随机数:

$
\left[\begin{array}{c}X\\ Y\end{array}\right]\sim\mathcal{N}\left(\left[\begin{array}{c}0\\ 1\end{array}\right],\left[\begin{array}{cc} 4 & 4.2\\ 4.2 & 9\end{array}\right]\right)
$

详细过程和结果参见下面这份PDF文档(点击下载):

A Simple Demo on Caching R Objects and Graphics with pgfSweave (PDF)

二维正态分布随机数及其等高线图
二维正态分布随机数及其等高线图

我们生成了50万行随机数,并画了X与Y的散点图。由于我们设定了相关系数为0.7,所以图中自然而然显现出正相关;而等高线也体现出多维正态分布的“椭球形”特征。均值在(0, 1)附近,都和理论分布吻合。所以这个Gibbs抽样还不太糟糕。

生成上面的PDF文档和图形的LyX/Sweave源文档在这里:

A Simple Demo on Caching R Objects and Graphics with pgfSweave (LyX)

如果你已经按照我前面的文章配置好你的工具(即使当时配置过,现在也需要重新配置,因为我最近作了重大修改),这个文档应该可以让你重新生成我的结果。文档中有两处关键选项:

  • cache=TRUE 使得文档中的R对象可以被缓存;
  • external=TRUE 使得图形可以被缓存;

第一次运行文档时,也许需要等待一分钟左右的时间,因为R需要长时间的Gibbs抽样计算,并编译生成的图形为PDF,但如果下一次再运行这个文档,则速度会快很多,因为不需要再计算任何东西,只需从缓存加载就可以了。我们前一次的抽样结果已经在缓存库中了。

本文至此可以结束,但真正想享用这个结果的读者可能还要继续看几个问题:

  1. pgfSweave对图形的缓存经常有点过度,即使你改动了代码,缓存仍然不会被替换,这种情况下你可以把生成的tikz和pdf图形删掉;
  2. 中文问题:tikzDevice包好像还没有完全解决中文问题,作者正在尝试我提供的中文图形,也许在未来不久的新版本中会有完全的中文支持,但目前实际上我已经在我的自动配置脚本中解决了这个问题。我们只需要保证我们的中文LyX文档用UTF-8编码就可以了——在文档选项中使用CTeX类(以及UTF8选项),并设置语言为中文、编码为Unicode (XeLaTeX) (utf8)。这种设置至少我在Windows和MikTeX下可以成功编译中文Sweave文档。目前高亮代码功能在中文文档中还不能用,但我已经向相关作者发了补丁,等CRAN管理员回来发布新版parser包之后这个问题也会解决。所以,中文用户也不必担心,一切都(将)可以使用。
  3. 依旧是样式问题:细心的读者也许能发现上面的PDF文档中的图形和这里网页中的图形略有区别,PDF文档中图形的字体和正文字体是一致的,这也是pgf的优势,前文第5节曾提到过。
  4. 如果使用缓存,那么代码段中的对象都无法打印出来,即使用print(dat)也无法打印dat,这是因为缓存的代码段只管是否加载对象,而无法执行进一步的操作(包括打印),对于这种情况,我们应该设计好我们的Sweave文档结构,让某些代码段作计算(并缓存),某些代码段作输出(不要缓存)。

这两篇文章都有点长,但最终的操作都极其简单。如果能理解这套工具,我想无论是写作业还是写报告,都将事半功倍(比如我就一直用它写作业)。

祝大家在新的一年能写出漂亮、利索的统计文档,告别复制粘贴的体力劳动。

用局部加权回归散点平滑法观察二维变量之间的关系

局部加权回归散点平滑法
局部加权回归散点平滑法

二维变量之间的关系研究是很多统计方法的基础,例如回归分析通常会从一元回归讲起,然后再扩展到多元情况。局部加权回归散点平滑法(locally weighted scatterplot smoothing,LOWESS或LOESS)是查看二维变量之间关系的一种有力工具。

LOWESS主要思想是取一定比例的局部数据,在这部分子集中拟合多项式回归曲线,这样我们便可以观察到数据在局部展现出来的规律和趋势;而通常的回归分析往往是根据全体数据建模,这样可以描述整体趋势,但现实生活中规律不总是(或者很少是)教科书上告诉我们的一条直线。我们将局部范围从左往右依次推进,最终一条连续的曲线就被计算出来了。显然,曲线的光滑程度与我们选取数据比例有关:比例越少,拟合越不光滑(因为过于看重局部性质),反之越光滑。 继续阅读用局部加权回归散点平滑法观察二维变量之间的关系