最有用的R把戏是什么?[关闭]


88

为了共享有关R的更多提示和技巧,您最有用的功能或诀窍是什么?聪明的向量化?数据输入/输出?可视化和图形?统计分析?特殊功能?交互环境本身?

每个帖子一个项目,我们将看看我们是否通过投票获得胜利者。

[2008年8月25日编辑]:因此,一周后,似乎简单人士str()赢得了投票。我想推荐一个人,这是一个容易接受的答案。


8
@Dirk:“社区Wiki”的意思是“社区拥有的”,它不是“投票问题”的同义词。不要听社区维基警察的话。
朱丽叶


8
CW再欺负。我会看到你的元SO,提高您:meta.stackexchange.com/questions/392/...
ARS

13
@ars:它是一个没有明确答案的问题。因此,使它成为CW。
dmckee ---前主持人小猫,

2
@JD长期热闹的评论。不幸的是,它被隐藏在折叠的后面。我的意思是回答棘手的R问题并不能真正解决问题。因此,如果我提出了让R出现在地图上的漂亮问题的家伙最终得到一点荣誉,那我就可以了。除此之外,R用户肯定比C程序员最喜欢的C技巧问题更有用
Matt Bannert 2010年

Answers:



64

我经常使用的一个非常有用的函数是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")

当您寻求帮助时,发布易于复制的数据块,或者编辑或重新排序因子的级别,可能非常有用。


42

head()和tail()获取数据帧,向量,矩阵,函数等的第一部分和最后部分。尤其是对于大型数据帧,这是一种检查其是否已正确加载的快速方法。


38

一项不错的功能:读取数据时使用的连接可以是本地文件,通过http访问的远程文件,其他程序的管道等。

举一个简单的例子,考虑对random.org(其基于大气噪声提供真实的随机数,而不是伪随机数生成器)提供的min = 100和max = 200之间的N = 10个随机整数的访问:

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


顺便说一句-如果(1)及时发布它们并且(2)您不提出问题CW ,我建议您应该进行自我回答CW。否则,看起来有点像您在尝试代表系统。YMMV等。
dmckee ---前主持人小猫,

1
这不是在玩系统,只是开始工作。他仍然可以接受其他任何答案。
ARS

2
@ars:他可以自由接受这个。如果他赢了,我也不会试图强迫他维基;不要听我的建议。但是我不会在没有标记维基的情况下发布准备好的自我解答,也不会在没有维基的情况下投票支持它。认为这是值得的。
dmckee ---前主持人小猫,

4
@德克:完全可以接受,甚至在杰夫和乔尔的鼓励下,回答您自己的问题。没有要求,甚至非正式的要求,使您的答案连续。您显然不是在玩系统。再一次,请忽略社区维基警察。
朱丽叶

8
我必须同意,网站的部分目的是为常见问题和一般资源提供最佳答案。提出问题并提供良好答案可以帮助加强话题。这是含新/小标记,如R.特别有用
kpierce8

35

我发现我正在使用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()是,您必须在评估的表达式中做一个赋值,然后赋值返回的对象(如上)才能获得理想的效果。


34

数据输入技巧= RGoogleDocs软件包

http://www.omegahat.org/RGoogleDocs/

我发现Google电子表格是让所有协作者都在同一个页面上的绝佳方式。此外,Google表单可让您捕获受访者的数据并将其毫不费力地写入Google电子表格。由于数据经常变化并且几乎永远不会改变,因此R最好直接读取google电子表格,而不要像futz那样下载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)

我不能忘记以下命令之一或两个需要花费几秒钟的时间。

  1. getGoogleAuth

  2. getGoogleDocsConnection

  3. getWorksheets


27

使用反引号引用非标准名称。

> 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  

[编辑]德克问为什么有人会给出无效的名字?我不知道!但是我当然在实践中经常遇到这个问题。例如,使用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

好的,但是为什么您需要用需要反引号的无效名称(例如1或2)替换语法上有效的名称(例如x或y)?
Dirk Eddelbuettel 09年

3
read.tablecheck.namesfalse为false时(例如,当您要使用原始列名时),它也很有用。
hadley

25

不知道这是多么众所周知,但是我肯定利用了环境的传递引用功能。

zz <- new.env()
zz$foo <- c(1,2,3,4,5)
changer <- function(blah) {
   blah$foo <- 5
}
changer(zz)
zz$foo

对于此示例,它为什么有用没有任何意义,但是如果您要传递较大的对象,则可能会有所帮助。


23

我最喜欢的新东西是foreach库。它使您能够完成所有不错的应用事情,但语法更简单:

list_powers <- foreach(i = 1:100) %do% {
  lp <- x[i]^i
  return (lp)
}

最好的部分是,如果您要执行的操作实际上需要大量时间,则可以从切换%do%%dopar%(使用适当的后端库)以立即进行并行化,甚至跨整个群集也可以。很好吃


19

我对数据做了很多基本的操作,因此这里有两个我日常使用的内置函数(transformsubset)和一个库(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()添加一列

## 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()切片数据

subset(sales, 
       country == 'USA' & product %in% c(1, 2), 
       select = c('product', 'revenue'))

>
  product  revenue
1       1 108.4597
4       2 100.3475

使用sqldf()进行SQL切片和聚合

所述sqldf包提供了一个SQL接口R数据帧

##  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

执行汇总或GROUP BY

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软件包。如果发现自己想拔头发,我建议您使用R检查数据操作


18
?ave

对“ x []”的子集进行平均,其中每个子集都包含具有相同因子水平的那些观测值。用法:ave(x,...,FUN =平均值)

我用它所有的时间。(例如,在此答案中,此处为so


这与tapply(x,factor,fun)有什么区别?
TMS

1
@Tomas ave保留顺序和长度。因此,例如,您可以一步将一组均值向量添加到数据集中。
爱德华多·莱昂尼

18

一种加快代码并消除for循环的方法。

而不是循环遍历数据框以查找值的for循环。只需将这些值作为df的子集,就可以更快。

所以代替:

for(i in 1:nrow(df)){
  if (df$column[i] == x) {
    df$column2[i] <- y
    or any other similiar code
  }
}

做这样的事情:

df$column2[df$column1 == x] <- y

该基本概念非常适用,并且是摆脱for循环的好方法


11
这里有一个小陷阱,一直困扰着我。如果df $ column1包含NA值,则使用==进行子集设置将提取等于x的所有值任何NA。为避免这种情况,请使用“%in%”而不是“ ==“。
马特·帕克

马特,您绝对正确,这是我讨厌的事情,不过我喜欢您的方法。我通常检查该列是否包含NA,然后使用我制作的快速函数将其删除,该函数接受一个dataframe列,并返回该NA中只有NAs的dataframe减去行。

本质上,我将数据帧缩减为我需要具有值的列,然后使用na.omit获取正确的行,然后仅使用这些行将原始数据集子集化。仅使用na.omit会删除具有任何NA的任何行,但我可能会误解。

16

有时您需要rbind多个数据框。 do.call()将允许您这样做(绑定时,有人不得不向我解释这个问题,因为这似乎没有什么用)。

foo <- list()

foo[[1]] <- data.frame(a=1:5, b=11:15)
foo[[2]] <- data.frame(a=101:105, b=111:115)
foo[[3]] <- data.frame(a=200:210, b=300:310)

do.call(rbind, foo)

好话:我发现这通常比使用更简单unsplit
Richie Cotton

16

一个R编程(不是交互式会话),我用if (bad.condition) stop("message")一个不少。每个函数都以其中一些开头,在我进行计算时,我也会加入其中。我猜想我assert()在C语言中养成了习惯。好处是双重的。首先,使用这些检查来获得工作代码要快得多。其次,也许更重要的是,当在编辑器的每个屏幕上看到这些检查时,使用现有代码会容易得多。你不会怀疑是否x>0,或信任的评论指出,这是...你会知道,从一看,是这样的。

PS。我在这里的第一篇文章。要温柔!


12
这不是一个坏习惯,R提供了另一种方式: stopfifnot(!bad.condition)更加简洁。
Dirk Eddelbuettel

13

traceback()当您在某个地方有错误并且不容易理解时,该功能是必须的。它将打印堆栈的痕迹,非常有用,因为R在默认情况下不是很冗长。

然后设置options(error=recover)将使您可以“进入”引发错误的函数,并尝试了解确切发生的情况,就好像您完全控制了该错误并且可以browser()在其中放一个。

这三个功能确实可以帮助调试代码。


1
options(error=recover)是我最喜欢的调试方法。
Joshua Ulrich 2010年

12

我真的很惊讶没有人发布有关apply,tapply,lapply和sapply的信息。我在R中执行填充操作时所使用的一般规则是,如果我有一个进行数据处理或模拟的for循环,则尝试将其分解出来并用* apply替换。有些人回避* apply函数,因为他们认为只能传递单个参数函数。事实并非如此!就像传递带有参数的函数作为Javascript中的第一类对象一样,您可以在R中使用匿名函数来实现。例如:

 > sapply(rnorm(100, 0, 1), round)
  [1]  1  1  0  1  1 -1 -2  0  2  2 -2 -1  0  1 -1  0  1 -1  0 -1  0  0  0  0  0
 [26]  2  0 -1 -2  0  0  1 -1  1  5  1 -1  0  1  1  1  2  0 -1  1 -1  1  0 -1  1
 [51]  2  1  1 -2 -1  0 -1  2 -1  1 -1  1 -1  0 -1 -2  1  1  0 -1 -1  1  1  2  0
 [76]  0  0  0 -2 -1  1  1 -2  1 -1  1  1  1  0  0  0 -1 -3  0 -1  0  0  0  1  1


> sapply(rnorm(100, 0, 1), round(x, 2)) # How can we pass a parameter?
Error in match.fun(FUN) : object 'x' not found


# Wrap your function call in an anonymous function to use parameters
> sapply(rnorm(100, 0, 1), function(x) {round(x, 2)})
  [1] -0.05 -1.74 -0.09 -1.23  0.69 -1.43  0.76  0.55  0.96 -0.47 -0.81 -0.47
 [13]  0.27  0.32  0.47 -1.28 -1.44 -1.93  0.51 -0.82 -0.06 -1.41  1.23 -0.26
 [25]  0.22 -0.04 -2.17  0.60 -0.10 -0.92  0.13  2.62  1.03 -1.33 -1.73 -0.08
 [37]  0.45 -0.93  0.40  0.05  1.09 -1.23 -0.35  0.62  0.01 -1.08  1.70 -1.27
 [49]  0.55  0.60 -1.46  1.08 -1.88 -0.15  0.21  0.06  0.53 -1.16 -2.13 -0.03
 [61]  0.33 -1.07  0.98  0.62 -0.01 -0.53 -1.17 -0.28 -0.95  0.71 -0.58 -0.03
 [73] -1.47 -0.75 -0.54  0.42 -1.63  0.05 -1.90  0.40 -0.01  0.14 -1.58  1.37
 [85] -1.00 -0.90  1.69 -0.11 -2.19 -0.74  1.34 -0.75 -0.51 -0.99 -0.36 -1.63
 [97] -0.98  0.61  1.01  0.55

# Note that anonymous functions aren't being called, but being passed.
> function() {print('hello #rstats')}()
function() {print('hello #rstats')}()
> a = function() {print('hello #rstats')}
> a
function() {print('hello #rstats')}
> a()
[1] "hello #rstats"

(对于那些遵循#rstats的人,我也在此处发布了此内容)。

请记住,请使用Apply,Sapply,Lapply,Tapply和do.call!利用R的向量化优势。您永远不要走过一堆R代码并看到:

N = 10000
l = numeric()
for (i in seq(1:N)) {
    sim <- rnorm(1, 0, 1)
    l <- rbind(l, sim)
}

这不仅没有向量化,而且R中的数组结构没有像Python中那样增长(当空间用尽时,IIRC的大小增加一倍)。因此,每个rbind步骤必须首先增长l到足以接受rbind()的结果,然后再复制前一个l的内容。为了有趣,请在R中尝试上述操作。请注意需要花费多长时间(您甚至不需要Rprof或任何计时功能)。然后尝试

N=10000
l <- rnorm(N, 0, 1)

以下也比第一个版本好:

N = 10000
l = numeric(N)
for (i in seq(1:N)) {
    sim <- rnorm(1, 0, 1)
    l[i] <- sim
}

apply,sapply,lapply和tapply很有用。如果要将参数传递给诸如round之类的命名函数,则可以将其与apply一起传递,而不是编写匿名函数。尝试“ sapply(rnorm(10,0,1),round,digits = 2)”输出“ [1] -0.29 0.29 1.31 -0.06 -1.90 -0.84 0.21 0.02 0.23 -1.10”。
丹尼尔(Daniel)2009年

11

根据Dirk的建议,我将发布单个示例。我希望他们对这个观众不要太“可爱”(聪明,但我不在乎)或琐碎。

线性模型是R的基础。当自变量数量很多时,一个有两个选择。首先是它使用lm.fit(),它类似于Matlab接收设计矩阵x和响应y作为参数。这种方法的缺点是返回值是对象列表(拟合系数,残差等),而不是“ lm”类的对象,可以很好地加以总结,用于预测,逐步选择等。方法是创建一个公式:

> A
           X1         X2          X3         X4         y
1  0.96852363 0.33827107 0.261332257 0.62817021 1.6425326
2  0.08012755 0.69159828 0.087994158 0.93780481 0.9801304
3  0.10167545 0.38119304 0.865209832 0.16501662 0.4830873
4  0.06699458 0.41756415 0.258071616 0.34027775 0.7508766
   ...

> (f=paste("y ~",paste(names(A)[1:4],collapse=" + ")))
[1] "y ~ X1 + X2 + X3 + X4"

> lm(formula(f),data=A)

Call:
lm(formula = formula(f), data = A)

Coefficients:
(Intercept)           X1           X2           X3           X4  
    0.78236      0.95406     -0.06738     -0.43686     -0.06644  

如果您在每个帖子中选择一个并举例说明如何?然后,我们可以连续几天继续工作,并使用新命令发布新示例... [顺便说一句,我记得您需要as.formula(paste(...))才能使用公式。]
Dirk Eddelbuettel 09年

您不需要显式创建公式即可覆盖所有列,因为形式为“ y〜。-1”可以覆盖所有列。“。” 表示“除因变量外的所有列,而“-1”则排除示例中的常量。
2009年

对这个特定的示例来说是正确的,但是对于带有ncols >> nrows的X,我经常删除一些自变量,尤其是在分析的最后阶段。在这种情况下,从数据框名称创建公式仍然很方便。
09年

10

您可以分配从if-else块返回的值。

代替例如

condition <- runif(1) > 0.5
if(condition) x <- 1 else x <- 2

你可以做

x <- if(condition) 1 else 2

确切的工作原理是深奥的魔力。


6
您也可以像x <-ifelse(condition,1,2)这样进行,在这种情况下,每个分量都被矢量化。
Shane

Shane,可以,但是除非您真正深深地了解ifelse()的功能,否则您不应该这样做!这是一个容易被误解的人
Harlan 2010年

这有什么神奇之处?这就是if-then-else表达式在任何功能语言中的工作方式(不要与if-then-else 语句混淆)。非常类似于?:C语言的三元运算符。
弗兰克(Frank)

10

作为R的入门者和stat的新手,我喜欢unclass() 将数据框的所有元素打印为普通列表。

一目了然地查看完整的数据集,以快速发现任何潜在问题,这非常方便。


9

CrossTable()从该gmodels软件包中可以轻松访问SAS和SPSS样式的交叉表以及常规测试(Chisq,McNemar等)。基本上,它xtabs()具有出色的输出和一些其他测试-但确实使与异教徒共享输出变得更加容易。


不错!我使用gmodels不少,但错过了一个
作者Abhijit

好的答案,可以使我避免对异教徒过度解释桌子的事情,都是对时间的充分利用。
Stedy 2010年

7

确定地system()。在我的日常工作流程中,要能够从R环境内部访问所有的Unix工具(至少在Linux / MacOSX下),已变得非常宝贵。


1
这与我先前关于连接的评论联系在一起:您还可以使用pipe()从Unix命令或向Unix命令传递数据。有关help(connections)详细信息和示例,请参见。
Dirk Eddelbuettel 09年

6

这是将因子转换为数值的烦人的解决方法。(也适用于其他数据类型)

old.var <- as.numeric(levels(old.var))[as.numeric(old.var)]

2
也许您的意思是“变成字符”向量。在这种情况下,“ as.character(old.var)”更简单。
Dirk Eddelbuettel

1
我一直认为这个建议(可以在?factor上阅读)会被误导。您必须确保old.var是一个因素,并且这取决于您为R会话设置的选项。使用as.numeric(as.character(old.var))既安全又干净。
爱德华多·莱昂尼

确实不值得一票,但无论如何。这对我有用。
瑞安·罗萨里奥

瑞安-您可以修改代码吗?如果old.var <-factor(1:2); 您的代码会给出[1]“ 1”“ 2”(不是数字。)也许您是说as.numeric(levels(old.var)[old.var])?
爱德华多·莱昂尼

3
或稍微更有效:as.numeric(levels(old.var))[old.var]
hadley

6

尽管这个问题已经解决了一段时间,但我最近在SAS和R博客上发现了使用该命令的绝妙技巧cut。该命令用于将数据划分为类别,而我将以虹膜数据集为例,将其划分为10个类别:

> irisSL <- iris$Sepal.Length
> str(irisSL)
 num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
> cut(irisSL, 10)
  [1] (5.02,5.38] (4.66,5.02] (4.66,5.02] (4.3,4.66]  (4.66,5.02] (5.38,5.74] (4.3,4.66]  (4.66,5.02] (4.3,4.66]  (4.66,5.02]
 [11] (5.38,5.74] (4.66,5.02] (4.66,5.02] (4.3,4.66]  (5.74,6.1]  (5.38,5.74] (5.38,5.74] (5.02,5.38] (5.38,5.74] (5.02,5.38]
 [21] (5.38,5.74] (5.02,5.38] (4.3,4.66]  (5.02,5.38] (4.66,5.02] (4.66,5.02] (4.66,5.02] (5.02,5.38] (5.02,5.38] (4.66,5.02]
 [31] (4.66,5.02] (5.38,5.74] (5.02,5.38] (5.38,5.74] (4.66,5.02] (4.66,5.02] (5.38,5.74] (4.66,5.02] (4.3,4.66]  (5.02,5.38]
 [41] (4.66,5.02] (4.3,4.66]  (4.3,4.66]  (4.66,5.02] (5.02,5.38] (4.66,5.02] (5.02,5.38] (4.3,4.66]  (5.02,5.38] (4.66,5.02]
 [51] (6.82,7.18] (6.1,6.46]  (6.82,7.18] (5.38,5.74] (6.46,6.82] (5.38,5.74] (6.1,6.46]  (4.66,5.02] (6.46,6.82] (5.02,5.38]
 [61] (4.66,5.02] (5.74,6.1]  (5.74,6.1]  (5.74,6.1]  (5.38,5.74] (6.46,6.82] (5.38,5.74] (5.74,6.1]  (6.1,6.46]  (5.38,5.74]
 [71] (5.74,6.1]  (5.74,6.1]  (6.1,6.46]  (5.74,6.1]  (6.1,6.46]  (6.46,6.82] (6.46,6.82] (6.46,6.82] (5.74,6.1]  (5.38,5.74]
 [81] (5.38,5.74] (5.38,5.74] (5.74,6.1]  (5.74,6.1]  (5.38,5.74] (5.74,6.1]  (6.46,6.82] (6.1,6.46]  (5.38,5.74] (5.38,5.74]
 [91] (5.38,5.74] (5.74,6.1]  (5.74,6.1]  (4.66,5.02] (5.38,5.74] (5.38,5.74] (5.38,5.74] (6.1,6.46]  (5.02,5.38] (5.38,5.74]
[101] (6.1,6.46]  (5.74,6.1]  (6.82,7.18] (6.1,6.46]  (6.46,6.82] (7.54,7.9]  (4.66,5.02] (7.18,7.54] (6.46,6.82] (7.18,7.54]
[111] (6.46,6.82] (6.1,6.46]  (6.46,6.82] (5.38,5.74] (5.74,6.1]  (6.1,6.46]  (6.46,6.82] (7.54,7.9]  (7.54,7.9]  (5.74,6.1] 
[121] (6.82,7.18] (5.38,5.74] (7.54,7.9]  (6.1,6.46]  (6.46,6.82] (7.18,7.54] (6.1,6.46]  (5.74,6.1]  (6.1,6.46]  (7.18,7.54]
[131] (7.18,7.54] (7.54,7.9]  (6.1,6.46]  (6.1,6.46]  (5.74,6.1]  (7.54,7.9]  (6.1,6.46]  (6.1,6.46]  (5.74,6.1]  (6.82,7.18]
[141] (6.46,6.82] (6.82,7.18] (5.74,6.1]  (6.46,6.82] (6.46,6.82] (6.46,6.82] (6.1,6.46]  (6.46,6.82] (6.1,6.46]  (5.74,6.1] 
10 Levels: (4.3,4.66] (4.66,5.02] (5.02,5.38] (5.38,5.74] (5.74,6.1] (6.1,6.46] (6.46,6.82] (6.82,7.18] ... (7.54,7.9]

5

另一个把戏。某些软件包(例如glmnet)将设计矩阵和响应变量作为输入。如果要使模型具有所有要素之间的所有相互作用,则不能使用公式“ y〜。^ 2”。使用expand.grid()允许我们利用R强大的数组索引和向量运算。

interArray=function(X){
    n=ncol(X)
    ind=expand.grid(1:n,1:n)
    return(X[,ind[,1]]*X[,ind[,2]])
}

> X
          X1         X2
1 0.96852363 0.33827107
2 0.08012755 0.69159828
3 0.10167545 0.38119304
4 0.06699458 0.41756415
5 0.08187816 0.09805104

> interArray(X)
           X1          X2        X1.1        X2.1
1 0.938038022 0.327623524 0.327623524 0.114427316
2 0.006420424 0.055416073 0.055416073 0.478308177
3 0.010337897 0.038757974 0.038757974 0.145308137
4 0.004488274 0.027974536 0.027974536 0.174359821
5 0.006704033 0.008028239 0.008028239 0.009614007

3
如果建模函数不接受公式(这种情况很少见!),用model.matrix?构造设计矩阵会更好吗?
hadley

好一个。我不知道此功能的存在。上面的函数等效于model.matrix(〜。^ 2 -1,X)但是关于传递矩阵,除了glmnet之外,我经常将数组指针传递给自定义C函数。确实,我不知道如何将公式传递给函数。你有玩具的例子吗?
09年

5

我最喜欢的(即使不是有些非常规的)技巧之一是使用eval()parse()。这个例子也许说明了它如何有所帮助

NY.Capital <- 'Albany'
state <- 'NY'
parameter <- 'Capital'
eval(parse(text=paste(state, parameter, sep='.')))

[1] "Albany"

这种情况经常发生,使用eval()parse()有助于解决这种情况。当然,我欢迎您提供有关其他编码方式的反馈。


1
命名向量元素也可以做到这一点。
Dirk Eddelbuettel 09年

3
library(fortunes); fortune(106)如果答案是parse(),则通常应重新考虑问题。-Thomas Lumley R-help(2005年2月)
Eduardo Leoni

这是一个eval()和parse()有用的示例。这涉及到一个Bioconductor软件包,例如hgu133a.db,并且您尝试在其中获取有关探针集ID的各种信息。例如:library(hgu133a.db)参数<-'SYMBOL'mget('202431_s_at',env = eval(parse(text = paste('hgu133a',parameter,sep =''))))参数<-'ENTREZID 'mget('202431_s_at',env = eval(parse(text = paste('hgu133a',parameter,sep =''))))
andrewj

正如Dirk所说,最好使用命名矢量元素或`get(paste(state,parameter,sep ='。'))``
hadley

@Hadley,不知道您可以那样使用get()。谢谢。
andrewj


5

对于那些正在编写C的人来说,从R:进行调用.Internal(inspect(...))很方便。例如:

> .Internal(inspect(quote(a+2)))
  @867dc28 06 LANGSXP g0c0 [] 
  @8436998 01 SYMSXP g1c0 [MARK,gp=0x4000] "+"
  @85768b0 01 SYMSXP g1c0 [MARK,NAM(2)] "a"
  @8d7bf48 14 REALSXP g0c1 [] (len=1, tl=0) 2

4

d ='〜/ R代码/库/'

文件= list.files(d,'。r $')

对于(文件中的f){如果(!(f =='mysource.r')){print(paste('Sourcing',f))source(paste(d,f,sep =''))}}}

在启动与R进行的交互式会话中使用的各种实用程序时,我使用上述代码来获取目录中的所有文件。我确信有更好的方法,但是我发现它对我的工作很有用。执行此操作的行如下。

来源(“〜/ R代码/库/mysource.r”)


6
不要这样 写一个包。
Dirk Eddelbuettel

谢谢。我一直在看关于roxygen的一两个线程,看来我可能正在尝试编写一个简单的自用包的级别。
mcheema

3

对数据帧中的多个变量执行运算。这是从subset.data.frame中窃取的。

get.vars<-function(vars,data){
    nl <- as.list(1L:ncol(data))
    names(nl) <- names(data)
    vars <- eval(substitute(vars), nl, parent.frame())
    data[,vars]
    #do stuff here
}

get.vars(c(cyl:hwy,class),mpg)

1
起初看起来很酷,但是从长远来看,这种代码不会给您带来麻烦。明确一点总是更好。
hadley

哼,最近我一直在使用这个技巧。您能否更详细地说明其无限的麻烦?
伊恩·研究员2009年

也许hadley建议改用plyr软件包?
Christopher DuBois 2009年

3
不,这不是使用plyr的强烈建议。您的代码的基本问题是,它在语义上是惰性的-而不是让用户明确地拼出他们想要的内容,而是进行一些“魔术”猜测。这样做的问题是,这使得该函数很难编程-即,很难编写一个get.vars无需跳很多圈就可以调用的函数。
hadley

3

我以前曾经发布过一次,但是我使用了那么多,以为我会再次发布。它只是一个小功能,用于返回data.frame的名称和位置编号。没什么特别的,但我几乎从不通过多次使用它来完成它。

##creates an object from a data.frame listing the column names and location

namesind = function(df){

temp1=names(df)
temp2=seq(1,length(temp1))
temp3=data.frame(temp1,temp2)
names(temp3)=c("VAR","COL")
return(temp3)
rm(temp1,temp2,temp3)

}

ni <-namesind


4
这确实是一个data.frame(VAR = names(df), COL = seq_along(df))
单线

非常优雅,也许我将其切换为ni <-function(df){data.frame(VAR = names(df),COL = seq_along(df))}}
kpierce8

1
我使用:data.frame(colnames(the.df))
Tal Galili 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.