2008年12月5日星期五

R经验汇编

R使用经验

本文将以逐渐增加的方式总结一些R的小问题的处理方法。 这里的一部分小窍门来自Grant V. Farnsworth: Econometrics in R

重要链接

R-Forge: http://r-forge.r-project.org/ 各种R附加软件包的存放地点。

Access表读写

假设有Access数据库在文件c:/Friends/birthdays.mdb中,内有两个表MenWomen,每个表包含域Year, Month, Day, First Name, Last Name, Death。域名应尽量避免用空格。

例1:读入女性所有信息:

> require(RODBC)

> con <- odbcConnectAccess("c:/Temp/birthdays.mdb")

> women <- sqlQuery(con, 'select * from Women')

> print(women)

> close(con)

例2:显示数据库目录

> require(RODBC)

> con <- odbcConnectAccess("c:/Temp/birthdays.mdb")

> # Table names. Ignore those starting with 'MSys'

> sqlTables(con)$"TABLE_NAME"

> # Column names in a table

> sqlColumns(con, "Women")$"COLUMN_NAME"

> close(con)

例3:较复杂的查询

> require(RODBC)

> con <- odbcConnectAccess("c:/Temp/birthdays.mdb")

> # Read Year, Last Name and First Name.

> # Rename Last Name to LastName, First Name to FirstName

> # Read first 5 rows where First Name is not 'Carl'

> men <- sqlQuery(con, "select top 5 Year, [First Name] as FirstName, [Last Name] as LastName from Men where [First Name]<>'Carl'")

> close(con)


Excel表格读写



基本办法是转换为其他格式如CSV格式再读。在Windows下有xlsReadWrite包,可以读写.XLS文件。RODBC包也可以支持Excel文件的读写。
小量数据可以选中一个矩形区域复制,然后在R中用

> myDF <- read.delim("clipboard")

也可以从R中复制数据集:

> ## export 'iris' data to clipboard

> write.table(iris, "clipboard", sep = "\t", col.names = NA)

> ## then open up MS Excel and paste (ctrl-v) in iris data

用ODBC读取Excel文件:

> library(RODBC)

> MyExcelData <- sqlFetch(odbcConnectExcel("Test.xls"), sqtable = "Sheet1", na.strings = "NA", as.is = T)

> odbcCloseAll()

用xlsReadWrite的例子:

> library( xlsReadWrite )

> ### create some test bike data

> tdat <- data.frame( Price = c( 6399, 3699, 2499 ), Amount = c( 2, 3, 1 ),

Date = c( 39202, 39198, 39199 ), row.names = c( "Pro machine", "Road racer", "Streetfire" ) )

> ### write

> write.xls( tdat, "bikes.xls" )

> ### read and check: read as data.frame

> bikes1 <- read.xls( file = "bikes.xls" )

> if (!identical( tdat, bikes1 )) stop( "oops, not good..." )

> # read as data.frame (custom colnames, date as iso-string)

> bikes2 <- read.xls( file = "bikes.xls", colNames = c( "", "CHF", "Number", "Date" ),

from = 2, colClasses = c( "numeric", "numeric", "isodate" ) )

> if (!all( tdat$Date == isoStrToDateTime( bikes2$Date ) )) stop( "oops, not good..." )

> # read as matrix

> bikes3 <- read.xls( file = "bikes.xls", type = "double" )

> if (!identical( as.matrix( tdat ), bikes3 )) stop( "oops, not good..." )



简单交互式图形界面

R 通过对Tcl/Tk的支持(tcltk包)实现了图形界面(GUI)功能,但是需要的编程略微复杂。rpanel是建立在tcltk包基础上的一个包,它 用很简单的几个语句就可以建立一个调控运行参数的界面,主要用来实时更新图形,修改界面上的控制参数则图形立刻刷新。真的很容易。



表格数据

table()计算频数。

tapply(x, fac, func)facx分组在每组内计算函数funcfac还可以是由若干因子向量组成的列表,这时将交叉分类后计算func函数。

几个因子完全组合的结构数据集可以用expand.grid(li)实现,li是一个列表,每个列表变量包含一个因子的水平。如果ll是某个包含若干因子变量的列表,则expand.grid(lapply(ll, levels))可以构造所有可能水平组合的数据框。


要把矩阵按其显示格式写入一个文本文件,办法如

write(t(A), file="filename", ncolumns=ncol(A)).


C++/C中使用NA

有时需要把NA传到C++/C中。为此,C中要包含R.h头文件,并用ISNA(x[0])这样的方法判断x[0]是否为NA,编译时最好用标准的

R CMD SHLIB yourcprog.cpp

方法编译。在R中调用时.C中要加上NAOK=TRUE选项。


Linux中非超级用户安装包

假设你在自己的主目录下建立了.R/library子目录,并建立了一个~/.Renviron文件,其中包含如下行:

R_LIBS=”~/.R/library”

则可以把R的附加包安装在自己的目录中:
R CMD INSTALL -l ~/.R/library mypackage.tar.gz
进入R后可以直接访问在~/.Renviron中定义在R_LIBS目录中安装的包。


运行记录

数据分析运行中间可能输出大量的信息,在调试程序时可能需要查看这些信息。在Emacs中用ESS支持直接在Emacs窗口中运行R当然可以保存这些输出,但是在Emacs中运行如果出错(尤其是调用自己编写的C程序的错误)不容易恢复。用sink()函数可以保存输出到文件,但这时在屏幕上就看不到输出。其实,sink()函数加一个split=TRUE选项就可以实现既输出到文件同时又显示在屏幕的效果。如果图形也能作到这点就好了。


R命令行中设置当前工作目录

getwd()查询当前工作目录,用setwd('subdir')设置当前工作目录。 调用list.files()可以查看当前目录中内容, 用list.files(pattern='.*[.]r$')可以列出所有以“.r”结尾的文件。


集合函数

union(x, y)
intersect(x, y)
setdiff(x, y)
setequal(x, y)
is.element(el, set)

fft的数学公式

Rfft函数可以进行离散傅立叶变换。 设x为长度n的向量,y=fft(x),则
y[k] = sum(x * complex(argument = -2*pi * (0:(n-1)) * (k-1)/n))

w_k = \frac{k-1}{n}, k=1,2,...,n
y_k = \sum_{j=1}^n x_j \exp(-i 2\pi w_k (j-1)).
注意没有除以n。另外,若y=fft(x), z=fft(y, inverse=T), x == z/length(x)


R的日期类

DateR的日期类,实际保存为实数值。转换如d=as.Date("1996-03-17", format="%Y-%m-%d"), 而显示可用如format(d, format="%Y-%m-%d")。格式中%Y是四位的年份,%m是数字的月份,%d是日期,%y是两位的年份,%b是英文所写的月份,%B是英文全称的月份。参见strptime的帮助。


顺便提一句,在SAS中如果要把如s=”1997-03-15”这样的字符串值转换成SAS日期,方法是date=input(s, yymmdd10.)


数据框横向合并

merge 函数。


巨大文件的读取


先用file打开,然后用readLines分批读入, 或用scanwhat参数和nlines参数分批读入。


读入复制到系统剪贴板中的数据


read.table("clipboard")


回归系数估计的方差阵

rs <- summary(lm.res)
CovMat <- rs$sigma^2 * rs$cov


加权回归


只要在lm调用时加weight选项。


Logitprobit回归

glm


多项logit回归


nnet包中的multinom函数。


有序Logit/Probit


MASS包中的polr函数。


带删失变量的回归


survreg并指定dist="gaussian"即可。


分位数回归

quantreg包中的rq函数。


稳健回归

MASS包中的rlm函数。


非线性最小二乘

nls函数。


时间序列函数

lag可以计算滞后序列,但只能作用于时间序列对象,对一般向量会得出错误结果。 diff计算差分。ts.union可以形成多元时间序列。 filter函数可以计算递推的或卷积的滤波。 arima可以拟合ARIMA模型。 fracdiff库的fracdiff可以拟合分数ARIMA模型。 tseries包中的garch可以拟合GARCHARCH模型。 fSeries包中的garchFit可以拟合较复杂的包含GARCH的模型。 acfpacf函数可以作自相关和偏自相关图。


时间序列检验

car包中的durbin.watson函数可以对lm对象进行Durbin-Watson自相关检验。 ts包中的Box.test可以进行Box-PierceLjung-Box白噪声检验。 tseries包中的adf.test可以进行Dickey-Fuller单位根检验。


curve函数

用于函数或表达式作图,与add=T选项配合可以在已有的图上添加曲线。


等值线图

contour函数。可以用contourLines添加。 lattice包中有类似的levelplotcontourplot函数。


添加标注

text, lines, points, arrowslegend等。用locator定位。


输出到图形文件

直接用图形设备postscript, pdf, png, jpg, xfig等。


图中用数学符号

用如main=substitute(y==Psi*z-sum(beta[0]^gamma)),会变成数学符号。 下标用方括号表示。等号用两个等号表示。 还可以给substitute一个额外的list参数表示要代入实际值的变量。 混合文本如
main=substitute(paste("t-stat of ", beta[0]))


Kronecker

A %x% B表示。


优化

optim, nlm, optimize。 类似作用的有uniroot(一元方程求根)diriv(数值微分)constrOptim(约束优化)


数值积分

一元用integrate,多元用adapt包中的adapt函数。


代替循环的函数

对矩阵用apply,对列表用lapply,对向量用sapply


计时

system.time(表达式)计算一个表达式的运行时间; 用proc.time得到当前时间,两次调用的差表示时间间隔。


在为R准备的C程序中使用R的随机数发生器

要调入头,在生成随机数前调用GetRNGstate(),生成完毕调用SetRNGstate()。实际产生一个正态分布随机数如rnorm(0.0, 1.0)。编译用
R CMD SHLIB mycode.c


错误处理

options函数调用中设error=recover可以使得出错时进入调试状态。 设warn=1可以使警告信息输入不滞后。 设warn=0取消警告信息,而warn=2使警告信息变成错误。


输出为LaTeX

Hmisc包中的latex函数,如latex(summary(lm(y~x)))。 或用xtable包中的xtable函数。用Hmisclatex函数时,加NA=””可以把缺失值显示成空白,输出数据集时,行名将作为第一栏。


用RPanel建立图形界面

用rp.control()函数建立一个窗口,用title指定标题。返回值保存一个代表此窗口的列表变量,列表中为图形数据。rp.control多余的参数被保存在列表中。如:

density.panel <- rp.control(title="Density estimation",

y=A1203, sp=r/8)

其中y,sp,model是额外的变量,被存放在结果列表density.panel中。


在窗口中添加控件时以窗口变量为第一自变量,如:

rp.slider(panel=density.panel, var=sp, from=r/50, to=r/4,

action=density.draw, title="Bandwidth")

在density.panel窗口中增加一个滑块控件,其中var参数指定窗口列表中已有的变量sp,变量的值将由此控件修改。action是修改值时更新用的响应函数。响应函数density.draw以一个窗口变量为输入,并返回可能修改后的窗口变量。


rp.radiogroup添加单选钮,如:

rp.radiogroup(panel=density.panel, var=sp.method,

values=c("normal", "plug-in", "manual"),

title="Bandwidth Selection", action=density.draw)

其中var=sp.method在density.panel列表中定义一个sp.method变量并由此单选钮组选择其取值。


rp.checkbox添加复选框,如:

rp.checkbox(panel=density.panel, var=model,

title="Normal band", action=density.draw)

指定density.panel列表变量model并由此控件控制开关。


rp.doublebutton添加加减按钮,如:

rp.doublebutton(panel=density.panel, var=sp, step=1.02,

log=TRUE, range=c(diff(range(A1203))/50, NA),

title="Bandwidth")

结果是并排的减号和加号,可以控制一个窗口列表变量的增减。var=sp指定要控制的窗口列表变量,step是变化量,log=TRUE指定是用等比方式变化,range给出变换的界限。


R中tcltk包的使用

例子见 http://bioinf.wehi.edu.au/~wettenhall/RTclTkExamples/ 。Tcl/Tk的原始参考资料见 http://www.tkdocs.com/widgets/index.htmlhttp://www.tcl.tk/man/tcl8.5/contents.htm


要先有一个主窗口,用tktoplevel生成,如:

root <- tktoplevel()

要指定窗口标题,用如:

tktitle(root) <- "tcltk测试"


生成按钮用command指定操作,如:

exit.but <- tkbutton(root,text="退出", command=function() tkdestroy(root))

tkgrid(exit.but) ## 用来摆放按钮

tkfocus(root)

按钮的对应操作是关闭窗口。


提示信息对话框:

res <- tkmessageBox(title="计算程序", message="试验时间数据输入错误!", icon="error",type="ok")

可以用icon="info", icon="warning"。如果type="yesnocancel"结果会有三个按钮, 用default="yes"指定缺省按钮。用as.character(res)查看结果。


用tclVar建立tcl变量,用tclvalue访问其值,如:
done <- tclVar(0) ## 建立tcl变量done, 值为0.
OK.but <- tkbutton(root, text=" OK ", command=function() tclvalue(done)<-1)
按钮的作用是把tcl变量done的值赋值为1. 可以用tclvalue(done)访问这个值,如果是整数应该用as.integer(tclvalue(done))转换。

用tkbind给某个窗口事件规定响应,如:
tkbind(root, "", function() tclvalue(done) <- 2)

用tkwait.variable等待tcl变量的值改变,如:
tkwait.variable(done)

用tklabel添加一个标签控件,如:
tkgrid(tklabel(root,text="This is a text label"))
如果需要修改标签内容,可以用tcl变量,如:
labelText <- tclVar("This is a text label")
label1 <- tklabel(root,text=tclvalue(labelText))
tkconfigure(label1,textvariable=labelText) ## 把控件与tcl变量关联。
tkgrid(label1)
ChangeText <- function() tclvalue(labelText) <- "This text label has changed!"
ChangeText.but <- tkbutton(tt,text="Change text label",command=ChangeText)
tkgrid(ChangeText.but)
其中用了tkconfigure把标签控件label1与变量labelText建立了联系。

用tkentry指定文本输入条,如:
tcl.en <- tclVar(1.5)
en <- tkentry(root, textvariable=tcl.en, width=20)
这样可以用as.double(tclvalue(tcl.en))访问输入的值。

用tktext指定文本输入框,如:
txt <- tktext(root, width=20, height=10)
其中宽和高的单位是字符。访问内容如:
s <- as.character(tclvalue(tkget(txt, "0.0", "end"))) ## 全部内容
s <- gsub(",", " ", s) ## 把逗号替换成空格
sc <- textConnection(s) ## 生成输入流
x <- scan(sc)
close(sc)

用tkframe作为容器容纳控件。如:
fr <- tkframe(root, padx=5, pady=5)
其 中padx和pady是在其必须的大小上加富余的空白。用relief和borderwidth指定边界形式,relief有raised, sunken, flat, ridge, solid, groove, 必须指定borderwidth如borderwidth=3才能显示效果。

用tkwidget生成一个一般Tk控件,用type指定类型,如:
fr <- tkwidget(root, type="labelframe", text="选择")

摆放控件用tkpack或tkgrid。tkpack沿上、下、左、右之一边缘摆放,tkgrid可以对准摆放,比如,la1和en1是输入的标签和输入条,la2和en2是另一对,则用
tkgrid(tklabel(root, text="输入部分"), columnspan=2)
tkgrid(la1, en1)
tkgrid(la2, en2)
其中第一个“输入部分”标签占了两列。在tkpack中用padx和pady指定左右和上下的间隙,如:
tkpack(ok.but, side="bottom", padx=10, pady=20)

在MS Windows环境下,为了能单独运行图形界面而不显示R原来的图形界面,可以在程序最后写上:
tcl.exit <- tclVar(0)
tkbind(root, "", function() tclvalue(tcl.exit) <- 1)
tkwait.variable(tcl.exit)
这样在批运行时不至于马上结束。批运行的命令是
\pathToRInstall\bin\rcmd BATCH testtk.r

\pathToRInstall\bin\rterm --vanilla <>&1

没有评论: