每个帖子一个功能或技巧,我们将通过投票来决定哪个最有用。
[编辑25-Aug 2008]:经过一周的投票,似乎简单的
str()
赢得了比赛。由于我自己也喜欢推荐它,所以这是一个容易接受的答案。 str()
赢得了比赛。由于我自己也喜欢推荐它,所以这是一个容易接受的答案。我经常使用的一个非常有用的函数是dput(),它允许您以R代码的形式导出对象。
# Use the iris data set
R> data(iris)
# dput of a numeric vector
R> dput(iris$Petal.Length)
c(1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6,
1.4, 1.1, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1, 1.7, 1.9,
1.6, 1.6, 1.5, 1.4, 1.6, 1.6, 1.5, 1.5, 1.4, 1.5, 1.2, 1.3, 1.4,
1.3, 1.5, 1.3, 1.3, 1.3, 1.6, 1.9, 1.4, 1.6, 1.4, 1.5, 1.4, 4.7,
4.5, 4.9, 4, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4, 4.7,
3.6, 4.4, 4.5, 4.1, 4.5, 3.9, 4.8, 4, 4.9, 4.7, 4.3, 4.4, 4.8,
5, 4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5, 4.7, 4.4, 4.1, 4,
4.4, 4.6, 4, 3.3, 4.2, 4.2, 4.2, 4.3, 3, 4.1, 6, 5.1, 5.9, 5.6,
5.8, 6.6, 4.5, 6.3, 5.8, 6.1, 5.1, 5.3, 5.5, 5, 5.1, 5.3, 5.5,
6.7, 6.9, 5, 5.7, 4.9, 6.7, 4.9, 5.7, 6, 4.8, 4.9, 5.6, 5.8,
6.1, 6.4, 5.6, 5.1, 5.6, 6.1, 5.6, 5.5, 4.8, 5.4, 5.6, 5.1, 5.1,
5.9, 5.7, 5.2, 5, 5.2, 5.4, 5.1)
# dput of a factor levels
R> dput(levels(iris$Species))
c("setosa", "versicolor", "virginica")
当你寻求帮助时,发布易于重现的数据块或编辑/重新排序因子级别可以非常有用。
str()
函数可以展示对象的结构。
dir()
- 更有意义。 - Hamish Grubijanclass()
呢?它似乎可以显示类似的信息。为什么会有两个如此相似的命令? - hhhclass()
只是str()
显示的信息的一小部分。 - hadley使用head()和tail()函数来获取数据框、向量、矩阵、函数等的前几行和最后几行。尤其是对于大型数据框,这是一种快速检查是否已经正确加载的方法。
一个很好的特性:读取数据使用连接,这些连接可以是本地文件、通过http访问的远程文件、来自其他程序的管道或更多。
作为一个简单的例子,考虑从random.org获取N=10个介于min=100和max=200之间的随机整数的访问(该网站提供基于大气噪声而不是伪随机数生成器的真正随机数):
R> site <- "http://random.org/integers/" # base URL
R> query <- "num=10&min=100&max=200&col=2&base=10&format=plain&rnd=new"
R> txt <- paste(site, query, sep="?") # concat url and query string
R> nums <- read.table(file=txt) # and read the data
R> nums # and show it
V1 V2
1 165 143
2 107 118
3 103 132
4 191 100
5 138 185
R>
顺便说一下,random包提供了多个便利函数来访问random.org。
我发现自己越来越多地使用with()
和within()
。不再在代码中到处散落$
,也不需要将对象附加到搜索路径上。更重要的是,我发现with()
等函数可以使我的数据分析脚本的意图更加清晰。
> df <- data.frame(A = runif(10), B = rnorm(10))
> A <- 1:10 ## something else hanging around...
> with(df, A + B) ## I know this will use A in df!
[1] 0.04334784 -0.40444686 1.99368816 0.13871605 -1.17734837
[6] 0.42473812 2.33014226 1.61690799 1.41901860 0.8699079
with()
设定一个环境,用于评估R表达式。 within()
也是这样做的,但允许您修改用于创建该环境的数据对象。
> df <- within(df, C <- rpois(10, lambda = 2))
> head(df)
A B C
1 0.62635571 -0.5830079 1
2 0.04810539 -0.4525522 1
3 0.39706979 1.5966184 3
4 0.95802501 -0.8193090 2
5 0.76772541 -1.9450738 2
6 0.21335006 0.2113881 4
我第一次使用within()
时没有意识到的一点是,在进行表达式求值的过程中,必须执行一个赋值操作 并且 将返回的对象分配给变量(如上所示),才能获得期望的效果。
http://www.omegahat.org/RGoogleDocs/
我发现谷歌电子表格是让所有协作者都在同一页上的绝佳方式。此外,谷歌表单允许您从受访者那里捕获数据,并轻松地将其写入谷歌电子表格中。由于数据频繁更改且几乎永远不会是最终版本,因此直接读取谷歌电子表格比下载CSV文件并读取它们要好得多。
# Get data from google spreadsheet
library(RGoogleDocs)
ps <-readline(prompt="get the password in ")
auth = getGoogleAuth("me@gmail.com", ps, service="wise")
sheets.con <- getGoogleDocsConnection(auth)
ts2=getWorksheets("Data Collection Repos",sheets.con)
names(ts2)
init.consent <-sheetAsMatrix(ts2$Sheet1,header=TRUE, as.data.frame=TRUE, trim=TRUE)
我记不清是哪一个或两个以下的命令需要几秒钟的时间。
getGoogleAuth
getGoogleDocsConnection
getWorksheets
使用反引号来引用非标准名称。
> df <- data.frame(x=rnorm(5),y=runif(5))
> names(df) <- 1:2
> df
1 2
1 -1.2035003 0.6989573
2 -1.2146266 0.8272276
3 0.3563335 0.0947696
4 -0.4372646 0.9765767
5 -0.9952423 0.6477714
> df$1
Error: unexpected numeric constant in "df$1"
> df$`1`
[1] -1.2035003 -1.2146266 0.3563335 -0.4372646 -0.9952423
在这种情况下,df[,"1"]也可以起作用。但是反引号在公式内工作!> lm(`2`~`1`,data=df)
Call:
lm(formula = `2` ~ `1`, data = df)
Coefficients:
(Intercept) `1`
0.4087 -0.3440
[编辑] Dirk问为什么会给出无效的名称?我不知道!但我在实践中经常遇到这个问题。例如,使用hadley的reshape包:
> library(reshape)
> df$z <- c(1,1,2,2,2)
> recast(df,z~.,id.var="z")
Aggregation requires fun.aggregate: length used as default
z (all)
1 1 4
2 2 6
> recast(df,z~.,id.var="z")$(all)
Error: unexpected '(' in "recast(df,z~.,id.var="z")$("
> recast(df,z~.,id.var="z")$`(all)`
Aggregation requires fun.aggregate: length used as default
[1] 4 6
check.names
为 false 时,在 read.table
中使用它也很有用 - 即当您想使用原始列名进行操作时。 - hadley不知道这个是否广为人知,但我肯定已经利用了环境的按引用传递的能力。
zz <- new.env()
zz$foo <- c(1,2,3,4,5)
changer <- function(blah) {
blah$foo <- 5
}
changer(zz)
zz$foo
对于这个例子而言,使用它可能没有太多意义,但是如果你需要传输大型对象,那么它会很有用。
我最新喜欢的东西是 foreach 库。它让你可以做所有好用的 apply 操作,但语法更容易一些:
list_powers <- foreach(i = 1:100) %do% {
lp <- x[i]^i
return (lp)
}
最棒的是,如果你正在做一些实际需要大量时间的任务,你可以切换从%do%
到%dopar%
(使用适当的后端库)以立即并行化,甚至在集群中也可以。非常流畅。
我经常进行基本数据操作,因此这里介绍了两个内置函数(transform,subset)和一个库(sqldf),它们是我每天使用的工具。
sales <- expand.grid(country = c('USA', 'UK', 'FR'),
product = c(1, 2, 3))
sales$revenue <- rnorm(dim(sales)[1], mean=100, sd=10)
> sales
country product revenue
1 USA 1 108.45965
2 UK 1 97.07981
3 FR 1 99.66225
4 USA 2 100.34754
5 UK 2 87.12262
6 FR 2 112.86084
7 USA 3 95.87880
8 UK 3 96.43581
9 FR 3 94.59259
## transform currency to euros
usd2eur <- 1.434
transform(sales, euro = revenue * usd2eur)
>
country product revenue euro
1 USA 1 108.45965 155.5311
2 UK 1 97.07981 139.2125
3 FR 1 99.66225 142.9157
...
subset(sales,
country == 'USA' & product %in% c(1, 2),
select = c('product', 'revenue'))
>
product revenue
1 1 108.4597
4 2 100.3475
sqldf包提供了一个可以将R数据框转换成SQL表格,并通过SQL语句进行数据操作的接口。
## recast the previous subset() expression in SQL
sqldf('SELECT product, revenue FROM sales \
WHERE country = "USA" \
AND product IN (1,2)')
>
product revenue
1 1 108.4597
2 2 100.3475
执行聚合或按组分组
sqldf('select country, sum(revenue) revenue \
FROM sales \
GROUP BY country')
>
country revenue
1 FR 307.1157
2 UK 280.6382
3 USA 304.6860
如果想要在数据框上进行更复杂的类似于Map-Reduce的功能,请查看plyr包。如果你发现自己想要拔光头发,我建议查看Data Manipulation with R。