忆铁峰

铁峰姓朴,是西北农林科技大学水保所的青年教师,和我同岁, 之前在东北林业大学学习, 并在韩国江原道大学留学。铁峰做的是群落生态学中的密度制约,做得很出色。研究成果发表在国际主流刊物上,受到同行的关注。

初识铁峰是在2009年, 那一年我和研究组米湘成老师去小兴安岭伊春的凉水样地和五营采集DNA材料。这两个样地是东北林业大学金光泽教授负责建立的, 铁峰就在金光泽教授的实验室帮忙。这是与铁峰第一次见面: 他个头很高,相当魁梧,很健谈。当地保护区的宋科长和铁峰也都很熟,因为他是朝鲜族, 给他起了个外号:“铁棒”,但是他也不生气。在实验样地, 我们一起在凉水样地采集样品, 铁峰帮我们找材料, 穿梭在红松、落叶松和冷杉之间。晚上回来, 一边压标本, 一起聊天, 他就介绍自己在韩国留学的经历。我问他, 作为朝鲜族, 在韩国留学, 是什么感觉? 他说, 就是觉得自己还是中国人, 与朝鲜人还是很不同。

之后, 我们一直通过QQ联系。2010年, 2011年, 铁峰和东北林业大学的几位研究生到中国科学院植物研究所培训,我请他们吃饭, 一起聊密度制约,聊群落生态研究。

两年前, 铁峰到了陕西杨凌,成了西北农林科技大学的青年教师, 我们还经常通过QQ联络:聊聊学校, 聊未来的发展, 聊合作研究。

今年过年回家,我直到初一晚上才找到时间给能联系到的好友们发新年祝福消息,我写到“铁峰兄, 新年快乐, 万事如意!”谁料今早收到他姨母的回复,“他以离开这个世界啦 你还不知道吗? 我是他的姨。” 接着又收到铁峰妈妈的电话, 同我讲述了大约是十天前, 铁峰一个人去位于延安的实验样地, 不知什么原因, 栽倒在一个坑中, 发现时, 已经太晚了。我安慰了阿姨很久, 但是人已不在, 生者还需要坚强。

这样一位年轻的朋友就这么走了, 我心情非常沉重。铁峰,希望你在天国好好的。天堂里再没有文章压力,没有项目评审,没有做不完的实验, 没有一个人出差…….

铁峰的weibo
http://t.qq.com/Bonze_Tang

铁峰

http://www.escience.cn/people/piaotiefeng/index.html

为kml文件添加时间并转存为gpx航迹

为数码照片添加经纬度坐标, 若无gps航迹, 可用google earth绘制出路径。 然后用本文提供的R函数为kml中的数据点拟合时间, 并另存为gpx文件。生成的gpx文件可用来为照片添加地理坐标 (参见 http://blog.sciencenet.cn/blog-255662-864234.html )。

kml文件是google earth的一种标记语言, 属于xml格式。在google earth中绘制航迹时,只有经纬度,而无时间。

gpx文件也是一种xml文件,gps导出的航迹文件,由多个点组成, 顺序链接在一起, 核心部分由 经度, 纬度, 海拔, 以及时间组成, 其中经度, 纬度为WGS84坐标系,以度为单位。海拔单位为米, 时间格式为 2015-02-05T23:38:09Z, 按照坐标顺序, 第一个点时间最早。时间必须用世界时。

具体步骤操作如下:

  1. 在google earth绘制航迹, 保存为ttt.km

  2. 在R中, 用以下函数, 读取kml文件的坐标, 并拟合航迹的开始时间以及最后的时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
library(maptools)  ###导入需要maptools程序包
kml2timetag <- function(kmlfile = "ttt.kml",
start.time = "2015-02-04 21:39:36",
end.time = "2015-02-05 23:40:50",
csv.file = NULL)
#### kml2timetag 函数读取kml文件中的经纬度坐标
#### kml2timetag 函数, 用来读取kml文件, 拟定航迹上每个点的时间
#### 该函数假设每个点对应的时间均匀流逝。
#### 返回值为 data.frame, 共四列
#### (1) "longitude" (2) "latitude" (3) "altitude" (4)"time"
#### 并可以保存为csv文件, 在必要的情况下, 在excel中进行编辑。
{
require("maptools")
Sys.setlocale("LC_TIME", "English")
dat <- getKMLcoordinates(kmlfile = kmlfile, ignoreAltitude=FALSE)
start.time <- as.POSIXlt(start.time)
end.time <- as.POSIXlt(end.time)
time.zone = 8
points.time <- seq(start.time, end.time, length.out = nrow(dat[[1]]))
points.time2 <- format(points.time, "%Y-%m-%dT%H:%M:%SZ")
dat <- cbind(dat[[1]], points.time2)
colnames(dat) <- c("longitude", "latitude", "altitude", "time")
if(!is.null(csv.file)){
write.csv(dat, csv.file)
}
return(as.data.frame(dat))
}

tagkml2gpx <- function(dat, output = "res.gpx"){
#### tagkml2gpx 用来转换data.frame到
#### dat,为data.frame, 共四列, 列名必须为
#### (1) "longitude" (2) "latitude" (3) "altitude" (4)"time"
#### 即函数kml2timetag的返回值, 作为本函数的输入值
#### 输出值为gpx函数。
res <- c(
"<?xml version="1.0" encoding="UTF-8" standalone="no" ?>",
"<gpx>",
" <trk>",
" <name>Track written by tagkml2gpx</name>",
" <trkseg>")
for(i in 1:nrow(dat)){
res <- c(res,
paste(" <trkpt lat="",dat$latitude[i], "\" lon=\"",
dat$longitude[i], "\">", collapse = "", sep = ""),
paste(" <ele>", dat$altitude[i], "</ele>", sep = ""),
paste(" <time>", dat$time[i], "</time>", sep = ""),
" </trkpt>")
}
res <- c(res,
" </trkseg>",
" </trk>",
"</gpx>")
writeLines(res, output)
}

dat2 <- kml2timetag(kmlfile = "ttt.kml",
start.time = "2015-02-04 21:39:36",
end.time = "2015-02-05 23:40:50")
tagkml2gpx(dat2, output = "res.gpx")

用exiftool为照片添加经纬度并生成照片经纬度列表

exiftool是为数码照片管理exif信息的软件,虽然只有命令行,但使用起来十分方便。下面就介绍如何用exiftool和GPS航迹文件,为数码照片添加经纬度和海拔,同时介绍如何从照片中批量导出经纬度。

操作系统 Windows 10, 64bit
Exiftool: version 11.25, 2019-01-15

  1. 在野外, 将GPS和相机设定为相同时间,野外工作完成后保存航迹。野外工作结束,尽快从GPS导出航迹, 格式为gpx格式,例如 track20150131.gpx 。

  2. 从相机导出照片,到某文件夹下,注意路径中不能有中文(但文件名可以有中文), 例如D:/plantphotos/20150101, 命名为 IMG_0001.jpg, IMG_0002.jpg

  3. 下载 exiftool( http://www.sno.phy.queensu.ca/~phil/exiftool/ )的Windows可执行文件, 解压缩, 将 exiftool(-k).exe 重命名为 exiftool.exe , 拷贝到照片所在的路径。注意照片的完整路径不能有中文。

  4. 创建一个纯文本文件, 命名为 csv.mft,内容为:

$filename,$gpslongitude#,$gpslatitude#,$gpsaltitude#

该文件为csv文件的模板, 用于之后从每张照片的exif文件中导出经纬度。

  1. 创建一个纯文本文件, 命名为 run_exiftool_geotaging.bat,内容为:

    1
    2
    exiftool -geotag=track20150131.gpx ./
    pause
  2. 创建一个纯文本文件, 命名为 run_exiftool_creat_csv.bat,内容为

    1
    2
    exiftool -p csv.mft ./>test.csv
    pause
  3. 双击run_exiftool_geotaging.bat文件, exiftool从航迹提取信息, 并为该文件夹下对应时间的照片添加经纬度和海拔。

  4. 双击 run_exiftool_creat_csv.bat 文件, exiftool读取每张照片的经纬度和海拔, 并保存到相应.csv文件中。

  5. 该csv文件默认为UTF-8编码,用Excel打开时中文会出现乱码,为了能在Excel中能正常处理,可以用Notepad++打开,并将文件转换为UTF-8-BOM编码,再用Excel打开即可。

更多信息请参见: https://www.sno.phy.queensu.ca/~phil/exiftool/geotag.html

世上再无Stefan

惊闻瑞典Umea大学忘年好友Stefan Ericsson先生逝世, 心里十分悲痛。

Stefan是瑞典的植物分类学家,擅长蔷薇科植物的分类, 是Umea大学植物标本馆的馆长。2012年,Stefan带我参加了西博腾省的植物调查,这个项目已经进行了三十多年, 是他牵头的。

还记得, 在湛蓝的天空下,Stefan带我穿过满布岩高兰和蓝莓的森林;还记得, 我和他一起沿着溪流寻找荚果蕨和瑞典毛茛, 一起看獐耳细辛; 还记得一起坐在满布地衣的石头上和他以及Stacey一起聊天,他提到地衣是驯鹿的食物; 还记得他邀请我去他家做客, 并神秘兮兮得跟我讲, 家里突然长出来一棵大麻, 说是野鸟传播来的,…… 三个礼拜之前, 还和他在facebook上聊天,他说准备换一个一个新键盘, 说总是打错字。

Stefan的乐观, 一直激励着我。没有Stefan的世界, 少了那么多的幽默、机智和乐观。

你的音容笑貌宛在, Stefan, 一路走好。

http://www.floranordica.org/info/personer/stefane.html

http://www.umu.se/sok/english/staff-directory?languageId=1&uid=ster0007

Python举例: 输入三角形边长,判断所生成三角形和面积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import math
a,b,c = input("Input the length of sides separated by comma:")
if a + b > c and a + c > b and b + c > a:
p = (a + b + c)/2.0
temp = p * (p - a) * (p - b) * (p - c)
area = math.sqrt(temp)
if a == b or b == a or c == a:
if a == b == c:
res = "equilateral triangle"
elif math.fabs(a**2 + b**2 - c**2) < 1e-6 or math.fabs(b**2 + c**2 - a**2) < 1e-6 or math.fabs(c**2 + a**2 - b**2) < 1e-6:
res = "isosceles triangle"
elif math.fabs(a**2 + b **2 - c**2) < 1e-6 or (b**2 + c **2 - a**2) < 1e-6 or (c**2 + a **2 - b**2) < 1e-6:
res = "rightangled triangle"
else:
res = "Common triangle"
else:
res = "Not triangle"
if res != "Not triangle":
print("Area for this triangle is", area)
print("It is a", res)
else:
print("Not a triangle")

用QGIS生成地图一副完整地图

QGIS是开源的GIS软件,有良好的图形界面支持。在Windows, Linux以及MacOS下均可使用, 可以在http://www.qgis.org/en/site/ 下载。

下面简要记述如何用QGIS生成一幅地图。

  1. 双击 QGIS Desktop 2.2.0, 加载所需要的图层, 如shape文件, 则点击 Layer > add vector layer, 选择对应的shape文件。

  2. 在左侧的导航栏, 选择 properties, Style, 之后分层设色, 根据polygon的属性, 设置不同的值。

  3. Project > New Print Composor 输入名称

  4. 在新窗口中, 点击Layout> add Map > 之后在空白页面上选择要绘制地图的范围, 则地图会自动出现

  5. 继续点击Layout, 选择添加 scale bar, add legend, add Label,Add arrow等, 添加地图的重要部分。在右面的属性栏, 可以输入文字,或者进行属性调整。

  6. 在右面的item properties中, 选择 Main Properties > Scale 选择比例尺

  7. 显示边框以及刻度, Show grid

  8. 通过Background选择地图的空白背景

  9. 选择 Project>Export as PDF 即可。

2014年12月18日

herblabel R程序包打印植物标本标签 (2017年1月9日更新)

(2017年1月9日更新)

关于herblabel程序包的介绍, 请参考 http://www.biodiversity-science.net/CN/abstract/abstract10290.shtml
程序包下载 herblabel安装文件.zip 以及使用说明

用herblabel打印植物标本标签和鉴定标签

  1. 安装R软件 http://www.r-project.org/
    如: Windows: http://cran.r-project.org/bin/windows/base/

  2. 安装Rtools, Rtools含有读取xlsx文件所需的解压缩函数. 安装时应该允许Rtools修改启动路径, 以便从CMD中能够调用Rscript以及zip等命令.

https://cran.r-project.org/bin/windows/Rtools/

  1. 安装devtools程序包

在R的命令行中,输入:

1
install.packages("devtools")
  1. 从 github 安装 herblabel

    1
    2
    library(devtools)
    install_github("helixcn/plantlist")
  2. 安装openxlsx程序包, 用于读取内置的xlsx模板

    1
    install.packages("openxlsx")

    至此, herblabel及其相关的程序包安装完成.

  3. herblabel程序包的更新

Herblabel程序包会根据用户反馈的意见, 进行修改, 或者增加相应的功能, 因此每隔一段时间, 就发布发新版本.

更新该程序包, 请用如下R命令从github重新安装:

1
2
library(devtools)
install_github("helixcn/herblabel")

打印标本标签以及鉴定标签

标本标签以及鉴定标签所用的数据均保存在Excel模板中. 主要步骤如下:

  1. 填写Excel模板

herblabel程序包带有Excel模板, 该模板的位置如下:

system.file(“extdata”, package = “herblabel”)

模板分为两种:

(1) 基于Darwin Core的标本记录Excel文件, 名为 DARWIN_CORE_HERBARIUM_RECORDS.xlsx;

(2) 标本鉴定的Excel文件, ANNOTATION_TEMPLATE.xlsx

Excel模板各列如下:

  • GLOBAL_UNIQUE_IDENTIFIER: 条形码号
  • INSTITUTION_CODE:标本馆缩写
  • COLLECTION_CODE:标本馆号, 可能和条形码号相同
  • BASIS_OF_RECORD: 标本的类型, 一般为腊叶标本
  • PREPARATIONS: 标本的状态, 如 有花有果, 有花无果, 无花有果, 无花无果
  • HERBARIUM(必填): 标本馆名
  • TITLE:该植物所属地区, 如Plants of Yunnan
  • COLLECTOR(必填):采集人
  • ADDITIONAL_COLLECTOR:共同采集人
  • COLLECTOR_NUMBER(必填):采集号
  • DATE_COLLECTED(必填):采集日期, 建议格式 2015-8-6 表示 2015年8月6日, 标签中会自动转换为英文的年月日
  • LOCAL_NAME:当地名称, 这里可以填写中文名或完整的学名, 并用fill_dwc处理后自动填写上 科属种命名人等信息.
  • FAMILY(重要): 科名, 必须是拉丁文
  • FAMILYCN:中文科名
  • GENUS:属
  • SPECIES:种
  • AUTHOR_OF_SPECIES:种作者
  • INFRASPECIFIC_RANK:种下等级, 只能是 subsp., var. 或者f.中的一个.
  • INFRASPECIFIC_EPITHET:种下等级加词
  • AUTHOR_OF_INFRASPECIFIC_RANK: 种下等级作者
  • COUNTRY(必填):国家或者地区
  • STATE_PROVINCE(必填):省或者州
  • COUNTY(重要):县
  • LOCALITY(重要):小地点
  • LOCALITY_ORIGINAL:(地名原始信息, 如中文地名):
  • IMAGE_URL:标本照片的路径
  • RELATED_INFORMATION:与地名相关的附记
  • LAT_DEGREE(重要):纬度的度
  • LAT_MINUTE(重要):纬度的分
  • LAT_SECOND(重要):纬度的秒
  • LAT_FLAG(重要):纬度的标签, 北纬N, 南纬S
  • LON_DEGREE(重要):经度的度
  • LON_MINUTE(重要):经度的分
  • LON_SECOND(重要):经度的秒
  • LON_FLAG(重要):经度的标签, 东经E, 西经W
  • ELEVATION (重要):海拔
  • ATTRIBUTES (重要):关于形态的描述, 如树高, 花色, 果的颜色以及树皮等的描述
  • REMARKS (重要):关于生境以及伴生种的描述, 如 along the stream
  • CABINET:标本所保存的柜子.
  • DISPOSITION:该标本是否在馆, 是否外借等信息.
  • GEOREFERENCE_SOURCES:位置的数据来源, 是GPS直接读取的, 还是Google Earth或者其他来源
  • GEOREFERENCE_VERIFICATION_STATUS:地理位置是否经过确认
  • GEOREFERENCE_REMARKS:地理位置的准确度, 如50m
  • PROJECT:该标本的研究项目
  • IDENTIFIED_BY(重要):标本的鉴定人
  • DATE_IDENTIFIED(重要):鉴定的日期, 最好也是2015-8-6类似的格式
  • TYPE_STATUS:该标本是否为模式标本
  • PROCESSED_BY:本条记录的录入人
  • DATE_LASTMODIFIED:本条记录上次更改的日期
    假设 DARWIN_CORE_HERBARIUM_RECORDS.xlsx 保存在 D:/herbarium/, 则输入以下命令, 即可生成rtf标签:
    1
    2
    3
    4
    5
    6
    7
    8
    setwd("D:/herbarium/") ## 注意斜杠要向右
    library(herblabel)
    library(openxlsx)
    dat <- read.xlsx("DARWIN_CORE_HERBARIUM_RECORDS.xlsx")
    ### 检查拼写等
    herbarium_label(dat, outfile = "herbarium_labels.rtf")
    ### 不进行检查
    herbarium_label(dat, spellcheck = FALSE, outfile = "herbarium_labels_no_checking.rtf")

默认情况下, spellcheck = TRUE, 此时herbarium_label函数将进行(1) 物种有效性的检查 , 即是否是The Plantlist 网站上的接受名 (2)属的拼写检查 (3) 科的拼写检查 (4) 科属对应关系的检查。 在Remarks这一列中, 如有列出伴生种, 则拉丁文部分会自动转换为斜体。 如果未能转换成斜体, 则需要检查其拼写。 这些信息会在生成的RTF文件中给出提示。

  1. 鉴定标签的打印
    herblabel程序包自带了鉴定标签的模板, 在 R中输入 system.file(“extdata”, package = “herblabel”)
    可找到 ANNOTATION_TEMPLATE.xlsx 文件, 该文件包括如下的列:
  • PROJECT:鉴定整理标本的有关项目
  • TYPE_STATUS:是何种模式标本, 如果不是可不填
  • TYPE_REF:如果是模式标本, 则需要写清楚发表该种的文献
  • FAMILY:科
  • LOCAL_NAME:中文名, 或者完整的学名
  • GENUS(重要):属
  • SPECIES(重要):种
  • AUTHOR_OF_SPECIES(重要):种作者
  • INFRASPECIFIC_RANK(重要):种下单位, 只能包括 subsp., var. 或者 f.
  • INFRASPECIFIC_EPITHET(重要):种下单位加词
  • AUTHOR_OF_INFRASPECIFIC_RANK(重要):种下单位作者
  • ABBREVIATION(重要):鉴定人的名称 如 打印标签上, 鉴定人之前要显示 Det., 则此处应该输入 Det.
  • IDENTIFIED_BY(重要): 鉴定人
  • INSTITUTION:鉴定人的机构
  • DATE_IDENTIFIED(重要):鉴定日期
  • DET_NOTE:鉴定的依据, 或者附注
  • SPECIMEN_NUMBER:标本条形码号
  • COLLECTOR:采集人
  • COLLECTOR_NUMBER:采集号

打印鉴定标签:

将该ANNOTATION_TEMPLATE.xlsx 拷贝到 D:/herbarium/

填好相应的鉴定信息后, 在Rgui中运行如下命令:

1
2
3
4
5
setwd("D:/herbarium")
library(herblabel)
library(openxlsx)
dat <- read.xlsx("ANNOTATION_TEMPLATE.xlsx")
annotation_label(dat)

由herbarium_label函数和annotation_label生成的rtf文件, 可以用Microsoft Word打开, 进行进一步的调整 (如某些物种的斜体,或者间距的调整)。

3.从中文名匹配并填写学名,命名人和科属等信息

在打印标签时, 人们希望尽量输入少的数据,因为输入的内容越多,出错的几率也越大, 特别是植物的学名, 不少人对拉丁文的拼写并不熟悉, 很容易在输入时出现错误. 此外, 命名人的缩写有不同的格式, 稍有不慎, 拼写就会出问题. 此外, 将一个完整学名按照科, 属, 种加词, 命名人, 种下等级, 种下等级加词, 种下等级命名人填写, 也相当费时费力. 为此, herblabel程序包中提供了fill_dwc函数, 目的是, 依照模板中出现的中文名, 在herblabel内置的数据库内找到对应的学名, 并且查找该种对应的apgiii科, 并填写到模板中, 随后将学名按照属, 种加词, 命名人, 种下等级, 种下等级加词, 种下等级命名人等自动填写到模板中.

使用方法

在Excel模板DARWIN_CORE_HERBARIUM_RECORDS.xlsx中, 将中国植物志接受的中文名,或者plantlist给出的完整的拉丁名拷贝到对应Excel模板的 LOCAL_NAME 一列, 之后运行如下命令即可:

1
2
3
4
5
6
setwd("D:/herbarium/") ## 注意斜杠要向右
library(herblabel)
library(openxlsx)
dat <- read.xlsx("DARWIN_CORE_HERBARIUM_RECORDS.xlsx")
dwc_filled <- fill_dwc(dat) ### 检查拼写等
herbarium_label(dwc_filled, outfile = "herbarium_labels.rtf")

4.模板信息的保存与更新, 以及生成RTF文件的自动保存

如果用户不希望一次性打印Excel模板中所有的记录, 则应该用subset函数进行筛选 (参考 http://www.statmethods.net/management/subset.html). 但是更多人希望将每次打印的标本记录自动更新到一个完整的Excel记录中, 并且完整保存每次运行的Excel模板, 以及生成的RTF文件. 实际上笔者已经提供了运行herblabel程序包的R脚本 run_herblabel (https://github.com/helixcn/run_herblabel) .

使用方法如下:

  1. 下载 run_herblabel文件夹 (https://github.com/helixcn/run_herblabel/archive/master.zip, 并将master.zip解压缩到任意文件夹下, 如 D:/herblabel
  2. run_herblabel下有两个文件夹, 分别命名为 herbarium label 和 annotation label
    以herbarium_label文件夹为例, 该文件夹下有如下文件:
  3. 文件夹:DARWIN_CORE_DB_SAVE, 里面有一个excel文件 darwin_core_database.xlsx , 该文件用来保存所有输入的记录.
  4. 生成的标本标签文件: herbarium_labels_to_print.rtf, 可以用MS word打开并查看.
  5. 标本记录模板: herbarium_specimens_label_data.xlsx, 在此Excel文件中输入数据
  6. 运行herblabel的R脚本: print_label.R, 这是运行herblabel的核心程序, 如果你对R不熟悉, 请勿更改此R脚本, 该脚本用来提取当前文件夹的未知, 并且读取和保存相应的文件.
  7. 标签文件的记录: RTF history, 每次运行批处理文件生成的RTF标签均保存在这里, 以时间作为文件名.
  8. 用来调用print_label.R的Window批处理文件, 用来调用print_label.R来生成标签, 并保存相关文件.
  9. 每一次标本标签记录的Excel文件: xlsx history

使用方法, 仅需配置好Rscript.exe的启动路径, 然后双击.bat文件即可:

设置启动路径的目的在于, 通过cmd可以直接调用Rscript.exe, Rscript.exe函数可以直接发送R脚本到R, 无须开启GUI. 如, 安装的R软件版本为3.2.3,则需要找到Rscript.exe所在的路径, 并添加到启动路径PATH中方法如下: 右键点击:

我的电脑>属性>高级>环境变量>系统变量 PATH一项,点击“编辑”,检查是否具有以下路径。通常软件在安装时已经自动配置好了启动路径。如Window7 64bit, 可在原有的路径上手工添加:

“;C:Program FilesRR-3.2.4bin;C:Program FilesRR-3.2.4bini386;” (注意: 仅拷贝双引号里面的内容, 不包括双引号. 按照不同的系统, 应该以Rscript.exe的真实路径为准)到 PATH一项的最后. 首位的分号”;”必须保留.

填写好Excel模板, 双击 “Search Scientific Names and create RTF labels.bat” 文件, 即会弹出窗口, 进行标签信息的处理,直接生成标本标签, 并保存中间的所有结果.

引用herblabel程序包:

如果你使用了herblabel程序包, 请用如下方式引用

查看引用

citations(“herblabel”)

Jinlong Zhang (2016). herblabel: Making Labels for Herbarium

Specimens in RTF and More. R package version 0.4.4.

https://github.com/helixcn/herblabel

如果您对herblabel程序包有任何意见或建议, 请联系 jinlongzhang01@gmail.com 或 本人的qq 85168042

从黑球、白球到极大似然估计

Likelihood 是生态和进化数据分析中的重要概念, 表示在给定模型和参数时, 某一事件发生的可能性。最大似然估计,就是已知某一事件发生的状况,计算在给定模型时, 模型参数取什么样的值, 才能让当前事件的可能性最大。

这里的事件, 可以是从袋子里抽取一定次数, 所得黑白球的结果,也可以是比对好的DNA碱基序列, 也可以是物种丰富度和降水量对应关系数据等等。 因此说, 所谓的极大似然估计, 其实是对参数取值的估计。

在分析中,如果一件事情已经发生,在计算其Likelihood时,就是将理论上的各种状态相乘,获得联合概率密度。求该联合概率密度,在参数取什么值时, 保证联合概率密度最大, 就是极大似然估计。

例如: 假设从一个袋子里,随机抽取白球和黑球,每一次抽完, 都放回到袋子里,共抽取了100次, 得到80个黑球, 20个白球, 求袋子中, 黑球与白球的比例是多大时, 最有可能得到当前的结果?

分析: 袋子里的球, 非黑即白, 可以简化为, 二项分布, 即一件事情发生还是不发生的概率。 假设抽到黑球的概率为p, 那么抽到白球的概率为1-p。在本例子中,抽取100次, 抽到了80个黑球, 其概率为p^80, 而抽到白球的概率为 1-p, 发生了20次, 因此概率为 (1 - p)^20。 因此, 产生抽样结果的概率为p^80*(1 - p)^20,这就是联合概率密度。为了便于批量计算, 这里写成了R函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
### Likelihood函数, 用来计算在p取值不同时, 当前结果(即80个黑球, 20个白球)发生的可能性。 
likelihood <- function(p) {p^80*(1 - p)^20}

###生成p的取值序列,p值取0.01, 意思是 100个白球里面, 有1个黑球, 99个黑球。
### 不难想象, 这种情况下, 抽取100次, 抽到80个黑球的可能性一定很小。
p <- seq(0.01, 0.99, by = 0.001)

### 计算p不同取值时, 抽取到80个黑球, 20个白球的可能性(likelihood)。
res.like <- likelihood(p)

### 绘图
plot(res.like, type = "l", col = "red")


### 由于likelihood是概率的乘机, 一般都很小, 所以在取自然对数之后,更加方便计算机处理, 所以一般都取自然对数。
### 这就是loglikelihood。
loglikelihood <- function(p) {log(p^80*(1 - p)^20)}

### 计算log likelihoodres.loglike <- loglikelihood(p)
### 绘图, 可查看loglikelihood与参数p的关系
plot(res.loglike, type = "l", col = "red")


### 用optimize可以通过数值方法,求函数的极值。
optimize(loglikelihood, interval = c(0, 1),maximum = TRUE)
## $maximum
## [1] 0.7999832
##
## $objective
## [1] -50.04024

由于获得likelihood的最大值的解析解常常十分困难, 实际情况在求maximum likelihood时, 大部分会用到数值方法。而且也不一定是求最大值, 而是求函数的最小值。 具体可参考R软件的 optim, nlm等函数的帮助文档。

用R程序包plantlist查询和处理植物学名

plantlist是用来查询和处理植物学名的R程序包,自2013年发布以来,受到很多老师和同学的关注。R软件中,类似的程序包还有taxize(https://cran.r-project.org/web/packages/taxize/index.html)、Taxonstand([https://cran.r-project.org/web/packages/Taxonstand/index.html)](https://cran.r-project.org/web/packages/Taxonstand/index.html)等)[等](https://cran.r-project.org/web/packages/Taxonstand/index.html)等)。

相比之下plantlist的主要特点在于:

  1. 使用校对过的内置数据,使用过程中不需要连网。
    
  2. 优化了查询单个物种名是否为接受名的算法,速度比taxize更快
    
  3. 查询结果所显示的信息更加简洁清晰
    
  4. 支持用中文名批量查询学名
    

plantlist的主要功能

  1. 批量查询植物科属,内置的数据主要来源于The    Plant    List网站(www.theplantlist.org/),其中被子植物采用APGIII分类系统,同时提供维管植物每个科的编号,极大方便了植物标本的管理,方便植物名录处理等。
    
  2. 直接生成科/属/种的列表,    以便导入Phylomatic等软件生成进化树
    
  3. 用中文名批量查询植物学名以及科属
    
  4. 查询学名的接受状态以及完整学名等
    

plantlist包内的函数

  • `CTPL()` 用中文名查询每个种的科、属、分布、海拔、在中国的IUCN等级数据
    
  • `CTPL2()` 功能与CTPL类似,但`CTPL2()`只读写Excel文件,而CTPL在查询时可直接输入中文字符。
    
  • `status()` 查询每个学名在The    Plant List 1.1数据库中的接受状态(该数据库已经放在程序包中)
    
  • `taxa.table()` 基于TPL查询结果制作科、属、种列表,以便用Phylomatic软件建立进化树
    
  • `TPL()` 用学名查询目、科、属以及科在分类系统中的编号
    

内置数据

  • `acc_dat`:    The Plant List 1.1 网站上的所有接受名
    
  • `cnplants_dat`:    《中国植物名录》及每个种的科、属、分布、海拔、中国IUCN等级以及特有性等数据
    
  • `genera_dat`:    The Plant List 1.1 网站上的所有属名列表,因源数据有一些错误,绝大部分已经修订。
    
  • `orders_dat`:    Angiosperm Phylogeny Website (www.mobot.org/MOBOT/research/APweb/)    提供的各科所属的目。
    
  • `syn_dat`:    The Plant List 1.1 网站的异名数据库
    

软件安装

plantlist必须要先安装R才能使用。由于plantlist内部函数CTPL2函数需要使用openxlsx程序包读取xlsx文件,所以也要安装openxlsx所依赖的Rtools以及Rcpp,并配置好启动路径才能正常使用。

安装R软件

R软件下载的地址为:(http://cran.r-project.org/bin/windows/base/)。请尽量下载最新版本的R并按照默认路径安装。因为程序运行过程中涉及UTF8字符转换,所以R版本不能低于3.0.3。

图1.R软件windows版本下载页

图2.R软件3.3.1的登录界面

安装Rstudio

推荐用Rstudio的Console输入函数查询,这是因为在部分Windows系统中,R自带的RGui中无法正常输入汉字,而Rstudio较好地解决了字符编码和汉字输入的问题。建议所有文本文件都使用UTF-8编码,以降低出现乱码的机会。

Rstudio可以在(https://www.rstudio.com/products/rstudio/download/)下载。

安装Rtools

Rtools是编写R程序包的工具软件,含有读写xlsx文件所需的unzip和zip函数,安装时必须允许Rtools修改启动路径

Rtools的下载地址为(https://cran.r-project.org/bin/windows/Rtools/)。安装Rtools时须允许其修改系统路径systemPATH。

图3.Rtools下载页面,请以列表中第一行未冻结的版本为准

图4.安装Rtools时应该允许其修改systemPATH

Rtools安装完成后可以通过以下方式检查是否安装成功:

图5.在控制台中输入zip,如图所示,若未提示错误,则Rtools安装和配置成功

安装openxlsx程序包

openxlsx程序包用来读取和保存带有植物名录的xlsx模板,在Rconsole中输入:

1
install.packages("openxlsx")

然后,在弹出的窗口选择距离较近的CRAN镜像,openxlsx程序包会自动下载并安装好。部分地区由于网络限制,不一定能打开r-project网站的云服务,以致报错。此时可以用以下命令从指定的CRAN镜像网站安装:

1
install.packages("ctv", repos = "http://cran.R-project.org")

其中 http://cran.R-project.org 可替换为任何CRAN镜像名。CRAN镜像列表见以下网址:https://cran.r-project.org/mirrors.html

图6.通过install.packages命令安装openxlsx程序包

安装plantlist程序包

由于plantlist程序包内置的数据约20M,不便提交到CRAN。稳定版本在R-Forge(https://r-forge.r-project.org/R/?group_id=2052),最新版本的源代码保存在github。

图7.Rforge网站上plantlist的页面

从R-Forge下载安装

命令是:

1
install.packages("plantlist", repos="http://R-Forge.R-project.org")

从github下载和安装

plantlist的github网址是(https://www.github.com/helixcn/plantlist)。可使用如下命令安装:

1
devtools::install_github("helixcn/plantlist")

若尚未安装devtools程序包,需要输入以下命令安装:

1
install.packages("devtools")

至此,plantlist及其依赖的程序包都安装好了。

plantlist各函数的用法

在使用plantlist之前,必须用library(plantlist) 加载plantlist。查询每个函数的使用方法,请输入?``函数名,例如:?TPL即可查看TPL函数的帮助界面。

CTPL() 用中文名查询科、属、分布、海拔、IUCN等级数据

调用方式和参数如下: CTPL(taxa= NULL, print_as_list = TRUE)

其中taxa是植物的中文名, print_as_list 只是打印方式的选项,如果为TRUE,则用列表的方式打印。

注意:用列表的方式打印,只是为了显示的方便,本函数返回值为****data.frame, print_as_list参数并不会改变返回值的数据类型。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
library(plantlist)
CTPL(c("杨梅", "多花泡花树"))
CTPL(c("网脉实蕨", "江南星蕨"))
# 将结果保存到Excel文件中
library(openxlsx)
rrr <- CTPL(c("侧金盏花",
"多花泡花树",
"网脉山龙眼",
"绿樟",
"网脉实蕨"))
write.xlsx(rrr, "results.xlsx")# 纯文本文件的读写

# Save to UTF-8

writeLines(text = c("桃儿七", "连香树","水青树","绿樟","网脉实蕨"),
con = "test_species.txt",
useBytes = TRUE)

sp <- readLines("test_species.txt", encoding = "UTF-8")

CTPL(sp)

图8.CTPL的查询结果

CTPL2() 用中文名查询科、属、分布、海拔、IUCN等级数据

CTPL2可直接读取Excel文件第一列的数据,并以此和内置的cnplants_dat数据匹配,结果保存在自动生成的xlsx文件中。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Example of CTPL2
library(plantlist)
library(openxlsx)

species <- data.frame(plants = c("侧金盏花",
"多花泡花树",
"网脉山龙眼",
"绿樟",
"网脉实蕨",
"无根藤",
"黄樟",
"香叶树",
"山鸡椒",
"潺槁木姜子",
"豺皮樟",
"浙江润楠",
"广东润楠",
"广寄生",
"两广梭罗",
"假苹婆",
"地桃花",
"白背黄花稔",
"通泉草",
"野牡丹"))

write.xlsx(species, "species_to_search.xlsx")
CTPL2("species_to_search.xlsx")

图9.CTPL2的查询结果。

status() 查询每个学名在ThePlant List 1.1 的接受状态

函数的参数 status(species=NA, exact =TRUE, spell_error_max =NULL)

  • `species`为输入的字符串向量。
    
  • `exact`表示是否进行精确匹配,如果不是精确匹配,则所有能用grep正则表达式匹配的结果都会显示。一般建议用精确匹配。
    
  • `spell_error_max` 为所允许的最大的错误拼写的字母数量。
    
  • `status`函数对输入的species物种名大小写不敏感,物种名的前后以及中间允许有多个空格,species可以包括或者不包括命名人(变型f.之前的命名人除外)。
    

status函数可以查询变种var.亚种subsp.以及变型f.是否接受等信息.

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
library(plantlist)

## 建立物种名单
sp <-c("Elaeocarpus decipiens",
"Syzygium buxifolium",
"Daphniphyllum oldhamii",
"Loropetalum chinense",
"Rhododendron latoucheae",
"Rhododendron ovatum",
"Vaccinium carlesii",
"Schima superba")

### 检查名单内每个种的接受情况以及接受名
status(sp)

### 检查一个种的接受情况
status("Myrica rubra") ## 杨梅
status("Adinandra millettii") ## 杨桐
status("cyclobalanopsis neglecta ") ## 竹叶青冈
status("Lirianthe henryi") ## 大叶木兰
#### 同时检查几个学名的状态
status(c("Myrica rubra",
"Adinandra millettii",
"Machilus thunbergii",
"Ranunculus japonicus",
"Cyclobalanopsis neglecta"))

### Check the statusof a scientific name (with or without authorship)
### 查询学名是否接受
status("Hypoxis filifolia")

### Subspecies (withor without authorship)
### 查询亚种是否接受
status("Hypoxis kilimanjarica subsp. kilimanjarica")

### Variaty (with orwithout authorship)
### 查询变种是否接受
status("Hypoxis erecta var. aestivalis")

### Form (with orwithout authorship)
### 查询变型是否接受
status("Hypoxis hirsuta f. villosissima")

### 重要提示: 由于表示变型的 f. 有时也用于命名人中,
### 因此,用status函数在查询变型时, 请勿为种添加命名人,
### 但是变型的命名人可以提供或者不提供,具体为:
"Hypoxis hirsuta (L.)Coville f. vollosissima Fernald"# (不能处理)
"Hypoxis hirsuta f. vollosissima Fernald"#(能处理)
"Hypoxis hirsuta f. vollosissima"#(能处理)

taxa.table() 基于TPL查询结果制作科属种列表

查询结果多用于在Phylomatic软件中构建进化树。示例代码如下:

1
2
3
4
5
6
7
sp <- c( "Ranunculus japonicus",
"Anemone udensis",
"Ranunculus repens",
"Ranunculus chinensis",
"Solanum nigrum",
"Punica sp." )
res <- TPL(sp)taxa.table(res)

TPL()根据拉丁名,查询目、科、属、以及科的编号

TPL函数输入的数据必须是字符串格式的向量。可以查询科、属、种的相应信息,但是并不会提示学名是否为接受名。查询学名是否有效,请用status函数。

1
2
3
4
5
6
7
8
9
10
11
TPL("Carex") # 
查询薹草属
TPL("Apple")
# 查询苹果的英文名
splist <- c("Ranunculus japonicus",
"Solanum nigrum",
"Punica sp.",
"Machilus",
"Today",
"####" ) ### 查询多个种
res <- TPL(splist)

引用plantlist程序包

如果您使用了plantlist程序包,请通过以下方式引用:

JinlongZhang (2018). plantlist: Looking Up the Status of Plant ScientificNames based on The Plant List Database. R package version0.5.3. https://github.com/helixcn/plantlist/

致谢

感谢高芳銮、李嵘、张健、朱慧玲、刘冰、胡晓丽、冯嘉恩、黄世芳、俞筱押、胡海花、李家湘、刘水银、鲍志贵、张美霞、葛斌杰、孔德良、刘振稳、龙文兴、金建军、夏尚文、李霞、陶旺兰、李秋萍、易逸瑜、张璋、骆争荣、彭舜磊、郭文永、贾蕙君等各位老师同学提出宝贵意见和建议。

参考文献

  • 多识团队.    (2016至今).    多识植物百科. [http://doucet.ibiodiversity.net/](http://doucet.ibiodiversity.net/).
    
  • 刘冰,    叶建飞,    刘夙,    汪远,    杨永,    赖阳均,    曾刚,林秦文.    (2015). 中国被子植物科属概览:    依据    APG    III 系统.    生物多样性,    23(2), 225-231.
    
  • 环境保护部,    中国科学院    (2013)    《中国生物多样性红色名录——高等植物卷    》 电子版来源:    www.mep.gov.cn/gkml/hbb/bgg/201309/W020130917614244055331.pdf
    
  • Christenhusz,    M., Zhang, X. C., and Schneider, H. (2011a). A linear sequence of    extant families and genera of lycophytes and ferns. Phytotaxa.    19:7-54
    
  • Christenhusz,    M., Reveal, J., Farjon, A., Gardner, M. F., Mill, R. R., and Chase,    M. W. (2011b). A new classification and linear sequence of extant    gymnosperms. Phytotaxa. 19:55-70
    

基于贝叶斯法的线性模型参数估计

在探讨一些统计问题时, 人们有时候希望基于现有数据, 得到某些参数的概率密度分布。以便对参数的估计有更加深入的了解。此外,有时 模型过于相当复杂,精确的公式难以给出解析解, 人们希望用模拟的方法,基于现有的数据, 探讨某些参数的分布。 这里就必须要用到贝叶斯推断。

介绍贝叶斯推断, 则绕不过贝叶斯公式, 这是一个表示参数集theta以及数据y关系的概率公式。

根据贝叶斯公式

p(theta|y) = {p(y|theta)*p(theta)}/p(y)

其中theta为参数集, y为数据:

  • p(y|theta) 为给定参数下, 数据y出现的概率, 即Likelihood。

  • p(theta) 为参数集theta的先验分布,可假设为任何概率密度分布。

  • p(y)则称为normalizing constant, 一般并不关心其取值。

但是, 要获得给定数据下的参数的分布却并不容易,p(y)是极难获取的值。 幸运的是, 在统计学家发明了一种基于随机抽样的方法, 可以获得参数的近似分布, 而不必考虑p(y)。 这几种有两种最常用技术,都是基于蒙特卡罗马尔科夫链。

如果一个过程的参数, 在下一个时刻的状态仅与当前时刻有关, 而与之前的状态无关, 则该过程具有马尔科夫性。换句话说, 给定一个模型, 如果要估计的一系列参数theta1, theta2, theta3, …, theta0, 当前的取值为 theta1_present, theta2_present, theta3_present, …, thetaN_present, 下一个时刻的取值为theta1’, theta2’, theta3’, …, thetaN’, 每个参数在未来取值只与对应的参数在当前时刻的取值有关, 这样一个过程, 就是一个马尔科夫过程。 记录下所有时刻参数的变化, 就构成了马尔科夫链。现代统计学中,在求复杂贝叶斯积分时, 用到马尔科夫链以及一些随机抽样的方法, 获得参数的近似分布。 常用的有两种方法, 分别称为Gibbs Sampling和Metrapolis Sampling。

马尔科夫链每变化一次, 称为一代。在控制马尔科夫链的状态变化以及抽样函数设置合理的情况下, 蒙特卡罗马尔科夫链进行的代数越多, 则所得结果越接近最大似然估计的结果。

本文就尝试用后者对简单的线性回归进行参数估计。当然, 笔者作为初学者, 理解上难免出现错误, 还请各位读者指正。

以下是Metrapolis Hastings算法的简要介绍

(1)在参数空间指定一套参数的初始值,作为起始点。初始值可以随机给出。

(2)按照参数的先验概率分布, 在初始值的基础上, 每个参数进行一定量的随机变化,计算当前参数组合的概率密度。

(3)依据当前参数组合和起始点概率密度比值是否大于0到1之间的一个均匀分布的随机数来判断是否保留当前点。

(4)若当前点的概率密度大于该随机数,就称这种状态为接受状态,此时,在满足参数概率分布的前提下,继续随机抽取参数的组合,作为下一点,计算下一点的概率密度,并计算下一点概率密度和概率密度的比值,并继续循环。

(5)若当前点不能被接受,则继续在满足参数概率分布的前提下,继续生成随机数,作为新的参数组合,直到参数组合能够被接受为止。

更详细的理论介绍, 请参阅 http://cos.name/2013/01/lda-math-mcmc-and-gibbs-sampling/

以下用实例, 即用MCMC (基于Metropolis Hastings 抽样)估计线性回归模型的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

### 第一步 首先生成要拟合的数据
set.seed(12345) ### 设定随机数种子
x = 1:60 ### 生成x数据, 共60个点
beta0_actual = 20 ### beta0真实值为20
beta1_actual = 5 ### beta1真实值为5
sigma_actual = 15 ### sigma真实值为15
y = x*5 + 20 + rnorm(60, 0, 15) ## 生成y数据, 这里假设已知 beta1 = 5, beta0 = 20, mu = 0, sd = 15
plot(y ~ x) ### 绘图
# 本套模拟数据所应的 beta0, beta1
linmod <- lm(y ~ x)
summary(linmod)

### 第二步, 写出 似然函数, 因线性回归一般模式均可写成
### y = beta1*x + beta0 + error,
### 而error符合 N(0, sigma)
### 所有error的概率乘积, 即联合概率密度, 称为Likelihood
### 因为Likelihood数值往往很小,在计算机中为了便于计算, 一般都取自然对数,
### 因此此时dnorm()之外是相加sum()
LogLikelihood <- function(beta0, beta1, sigma){
R = y - x*beta1 - beta0
sum(dnorm(R, mean = 0, sigma, log = TRUE))
}
#### LogLikelihood(50, 6, 1)

#### 第三步给出先验分布
#### beta0, beta1, sigma等所要估计参数的先验分布, 先验分布与取值以及概率密度与统计分布无关。
#### 这里为了演示方便beta0prior,beta1prior 取自均匀分布。prior三者同时发生, 因此取联合概率密度。
#### min,max的范围,也是根据参数的可能取值范围而估计。
prior <- function(beta0, beta1, sigma){
beta0prior = dunif(beta0, min=-100, max=100, log = TRUE)
beta1prior = dunif(beta1, min=-100, max=100, log = TRUE)
sigmaprior = dnorm(sigma, mean = 0, sd = 10, log = TRUE)
return(beta0prior + beta1prior + sigmaprior)
}

### prior(5,5,1)
### 写出Proposalfunction, 控制马尔科夫链状态变化的强弱, 即每一次变化, 数值的大小。 Proposalfunction一般取对称分布的概率密度,一般取正态分布,这是决定坐标点(beta0, beta1, sigma)在空间移动快慢的函数, 其中sd的取值, 决定了链的冷热程度。
proposalfunction <- function(beta0, beta1, sigma){
return(rnorm(3, mean = c(beta0, beta1, sigma), sd= c(0.1, 0.5, 0.3)))
}

### 后验分布函数, 后验分布。 因为概率密度均已经取log, 所以这里概率相乘用加法即可。
posterior <- function(beta0, beta1, sigma){
return (LogLikelihood(beta0, beta1, sigma) + prior(beta0, beta1, sigma))
}

MCMC <- function(intialvalue, generations){
chain = matrix(rep(NA, ((generations+1) * 3)), ncol = 3) ## 为马尔科夫链准备一个矩阵, 三列, 分别放置beta0, beta1, sigma的值
colnames(chain) <- c("beta0", "beta1", "sigma") ## 为列命名
chain[1,] = intialvalue ## 读取初始值
for (i in 1:generations){ ## 开始循环, 循环次数按照代数而定
proposal = proposalfunction(chain[i,1], chain[i,2], chain[i,3]) ### 围绕当前状态, 生成一套新的参数, 即让状态变化一次
probab = exp(posterior(proposal[1], proposal[2], proposal[3]) - posterior(chain[i,1], chain[i,2], chain[i,3])) ### 计算新状态与旧状态概率的比值, 因为概率之前都已经取对数, 因此这里取减号。
if (runif(1) < probab){ ## 生成一个0到1之间的随机数,如果该随机数小于新旧状态的比值, 则从记录下新的状态, 作为下一个时刻的起始状态。
chain[i+1,] = proposal
}else{ ### 否则, 状态不变, 代数加1
chain[i+1,] = chain[i,]
}
}
return(chain)
}
res.chain1 <- MCMC(intialvalue = c(4,20,1), generations = 100000) ###初始值设定为 beta0 = 4, beta1 = 20, sigma = 1, 运行第一个马尔科夫链
res.chain2 <- MCMC(intialvalue = c(4,20,1), generations = 100000) ###初始值设定为 beta0 = 4, beta1 = 20, sigma = 1, 运行第二个马尔科夫链

####
par(mfrow = c(1, 3))
plot(res.chain1[,1], res.chain1[,2], type = "l") ### 可以清楚得看出, 随机取值点逐渐偏离初始值, 最后稳定在一个值附近
plot(res.chain1[,1], res.chain1[,3], type = "l")
plot(res.chain1[,2], res.chain1[,3], type = "l")
1 估计的参数的Burning In及马尔可夫链收敛后的变化

######################################################
############ 用coda程序包分析马尔可夫链 ##############
library(coda)
mcmc.res <- mcmc(res.chain1)
summary(mcmc.res)
plot(mcmc.res)

#### 马尔可夫链是否收敛, 进入平稳状态? #############
#### 以下几个判别标准可以帮我们诊断, 读者可以参阅相应函数的说明
mcmcchains = mcmc.list(mcmc(res.chain1), mcmc(res.chain2))
plot(mcmcchains)
2 trace plot以及概率密度分布
gelman.diag(mcmcchains)
gelman.plot(mcmcchains)
geweke.plot(mcmcchains)
geweke.diag(mcmcchains)
3 用gelman.plot检验马尔可夫链是否收敛

#### 查看Densityplot图, 显示所求参数的概率分布情况
autocorr.plot(mcmc(res.chain1))
densityplot(mcmcchains)
par(mfrow = c(1, 3))
densplot(mcmcchains)
par(mfrow = c(1, 3))
traceplot(mcmc(res.chain1))
xyplot(mcmc(res.chain1))

###################################################
#### 当然, 从初始值开始, 一直到马尔可夫链到达平稳状态之前,这部分的结果是不能用的, 要去除的代数,常常约定俗成,如运行100万代, 500万代,舍去之前的10%。 为了减少抽象中自相关的影响, 还会每隔多少代取一个状态等。 这些内容, 绝大部分贝叶斯软件都有现成的函数。
beta0_actual = 20 ### beta0真实值为 20
beta1_actual = 5 ### beta1真实值为5
sigma_actual = 15 ### sigma真实值为15
burnIn = 20000
acceptance = 1 - mean(duplicated(res.chain1[-(1:burnIn),]))
par(mfrow = c(2,3))
hist(res.chain1[-(1:burnIn),1],nclass=50, , main="Posterior of beta0", xlab="True value = red line" )
abline(v = mean(res.chain1[-(1:burnIn),1]), col = "blue")
abline(v = linmod$coefficients[1], col="red" )
hist(res.chain1[-(1:burnIn),2],nclass=50, main="Posterior of beta1", xlab="True value = red line")
abline(v = mean(res.chain1[-(1:burnIn),2]), col = "blue")
abline(v = linmod$coefficients[2], col="red" )
hist(res.chain1[-(1:burnIn),3],nclass=50, main="Posterior of sigma", xlab="True value = red line")
abline(v = mean(res.chain1[-(1:burnIn),3]) , col = "blue")
abline(v = sigma_actual, col="red" ) ## 注意这里用到的sigma并非来自数据本身。
plot(res.chain1[-(1:burnIn),1], type = "l", xlab="Generations" , ylab = "Beta0", main = "Chain values of beta0", )
abline(h = linmod$coefficients[1], col="red" )
plot(res.chain1[-(1:burnIn),2], type = "l", xlab="Generations" , ylab = "Beta1", main = "Chain values of beta1", )
abline(h = linmod$coefficients[2], col="red" )
plot(res.chain1[-(1:burnIn),3], type = "l", xlab="Generations" , ylab = "Sigma", main = "Chain values of sd", )
abline(h = sigma_actual, col="red" ) ## 注意这里用到的sigma并非来自数据本身。

图 4 参数的Bayes估计值与真实值的比较

参考: