Thủ thuật R hữu ích nhất là gì? [đóng cửa]


88

Để chia sẻ thêm một số mẹo và thủ thuật cho R , tính năng hoặc thủ thuật hữu ích nhất của bạn là gì? Vectơ hóa thông minh? Nhập / xuất dữ liệu? Hình dung và đồ họa? Phân tích thống kê? Chức năng đặc biệt? Môi trường tương tác chính nó?

Một mục cho mỗi bài đăng và chúng tôi sẽ xem liệu chúng tôi có nhận được người chiến thắng bằng số phiếu bầu hay không.

[Chỉnh sửa ngày 25 tháng 8 năm 2008]: Vì vậy, sau một tuần, có vẻ như đơn giản str()đã thắng cuộc bình chọn. Như tôi muốn tự mình giới thiệu điều đó, đó là một câu trả lời dễ dàng chấp nhận.


8
@Dirk: "community wiki" có nghĩa là "do cộng đồng sở hữu", nó không phải là từ đồng nghĩa với "câu hỏi thăm dò". Đừng nghe cảnh sát wiki cộng đồng.
Juliet


8
CW lại bắt nạt. Tôi sẽ xem meta-SO của bạn và nâng cao bạn: meta.stackexchange.com/questions/392/…
ars

13
@ars: đó là một câu hỏi không có câu trả lời chắc chắn . Ergo làm cho nó CW.
dmckee --- cựu điều hành kitten

2
@JD Long bình luận vui nhộn. thật không may nó đã được ẩn sau nếp gấp. Ý tôi là việc trả lời những câu hỏi R khó không thực sự trả cho stack-rep khôn ngoan. Vì vậy, tôi không sao cả nếu những người đặt ra những câu hỏi hay để đưa R lên bản đồ cuối cùng cũng nhận được tín dụng. Bên cạnh đó là chắc chắn hữu ích hơn cho người sử dụng R hơn một cứu xem lỗi gì yêu thích câu hỏi C lừa của bạn sẽ được các lập trình viên C ...
Matt Bannert

Câu trả lời:


64

str() cho bạn biết cấu trúc của bất kỳ đối tượng nào.


Python sử dụng dir()- có ý nghĩa hơn.
Hamish Grubijan

17
Ah, strcũng là viết tắt của stringnhiều ngôn ngữ.
Hamish Grubijan

Tại sao không class()? Nó dường như tiết lộ loại thông tin tương tự. Tại sao lại có hai lệnh giống nhau như vậy?
hhh

1
class()chỉ là một phần nhỏ của thông tin str()hiển thị
hadley

64

Một hàm rất hữu ích mà tôi thường sử dụng là dput (), cho phép bạn kết xuất một đối tượng dưới dạng mã 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")

Nó có thể rất hữu ích khi đăng các phần dữ liệu có thể tái tạo dễ dàng khi bạn yêu cầu trợ giúp hoặc chỉnh sửa hoặc sắp xếp lại các cấp độ của một yếu tố.


42

head () và tail () để lấy phần đầu và phần cuối của dataframe, vector, matrix, function,… Đặc biệt với những khung dữ liệu lớn thì đây là cách nhanh chóng để kiểm tra xem nó đã tải chưa.


38

Một tính năng hay: Đọc dữ liệu sử dụng các kết nối có thể là tệp cục bộ, tệp từ xa được truy cập qua http, đường dẫn từ các chương trình khác hoặc hơn thế nữa.

Ví dụ đơn giản, hãy xem xét quyền truy cập này cho N = 10 số nguyên ngẫu nhiên từ min = 100 đến max = 200 từ random.org (cung cấp các số ngẫu nhiên thực sự dựa trên nhiễu khí quyển chứ không phải là trình tạo số ngẫu nhiên giả):

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>

Ngoài ra, gói ngẫu nhiên cung cấp một số chức năng tiện lợi để truy cập random.org .


BTW-- Tôi khuyên bạn nên đặt CW selfanswers nếu (1) bạn đăng chúng ngay lập tức và (2) bạn không đặt câu hỏi CW. Nếu không, có vẻ như bạn đang cố gắng chơi hệ thống đại diện. YMMV và tất cả những điều đó.
dmckee --- cựu điều hành kitten

1
Nó không phải là chơi trò chơi hệ thống, chỉ là bắt đầu mọi thứ. Anh ấy vẫn tự do chấp nhận bất kỳ câu trả lời nào khác.
ars

2
@ars: Anh ấy thoải mái chấp nhận cái này. Tôi cũng không cố gắng bắt anh ta wiki nó nếu anh ta thắng; tôi không nghe lời khuyên của tôi. Nhưng tôi sẽ không đăng một selfanswer đã chuẩn bị sẵn mà không đánh dấu wiki, và tôi cũng sẽ không bỏ phiếu cho một bài mà không có nó. Hãy lấy điều đó cho những gì nó đáng giá.
dmckee --- cựu điều hành kitten

4
@Dirk: hoàn toàn có thể chấp nhận được, thậm chí được cả Jeff và Joel khuyến khích trả lời câu hỏi của chính bạn. KHÔNG có yêu cầu nào, thậm chí không phải là không chính thức, để đưa ra câu trả lời CW của bạn. Rõ ràng là bạn không chơi hệ thống. Một lần nữa, hãy phớt lờ cảnh sát wiki cộng đồng.
Juliet

8
Tôi phải đồng ý rằng một phần của mục đích trang web là cung cấp câu trả lời tốt nhất cho các vấn đề chung và một nguồn tài nguyên chung. Đặt câu hỏi và đưa ra câu trả lời tốt có thể giúp củng cố chủ đề. Điều này đặc biệt hữu ích với mới / thẻ nhỏ như R.
kpierce8

35

Tôi thấy tôi đang sử dụng with()within()ngày càng nhiều hơn. Không còn $rải rác mã của tôi và người ta không cần bắt đầu gắn các đối tượng vào đường dẫn tìm kiếm. Nghiêm túc hơn, tôi thấy with()vv làm cho ý định của các kịch bản phân tích dữ liệu của tôi rõ ràng hơn nhiều.

> 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()thiết lập một môi trường trong đó biểu thức R được đánh giá. within()làm điều tương tự nhưng cho phép bạn sửa đổi đối tượng dữ liệu được sử dụng để tạo môi trường.

> 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

Có điều tôi đã không nhận ra khi lần đầu tiên sử dụng within()là bạn phải thực hiện một phép gán như một phần của biểu thức được đánh giá gán đối tượng trả về (như ở trên) để có được hiệu quả mong muốn.


34

Thủ thuật nhập dữ liệu = gói RGoogleDocs

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

Tôi nhận thấy bảng tính Google là một cách tuyệt vời để tất cả các cộng tác viên ở trên cùng một trang. Hơn nữa, Google Biểu mẫu cho phép người ta thu thập dữ liệu từ người trả lời và dễ dàng ghi dữ liệu đó vào bảng tính google. Vì dữ liệu thay đổi thường xuyên và hầu như không bao giờ là cuối cùng nên R thích đọc bảng tính google trực tiếp hơn là tải các tệp csv xuống và đọc chúng trong tương lai.

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

Tôi không thể ghi nhớ lại nhưng một hoặc hai lệnh sau mất vài giây.

  1. getGoogleAuth

  2. getGoogleDocsConnection

  3. getWorksheets


27

Sử dụng dấu gạch ngược để tham chiếu các tên không chuẩn.

> 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

Trong trường hợp này, df [, "1"] cũng sẽ hoạt động. Nhưng dấu tích lại hoạt động bên trong công thức!

> lm(`2`~`1`,data=df)

Call:
lm(formula = `2` ~ `1`, data = df)

Coefficients:
(Intercept)          `1`  
     0.4087      -0.3440  

[Chỉnh sửa] Dirk hỏi tại sao người ta lại đặt tên không hợp lệ? Tôi không biết! Nhưng tôi chắc chắn gặp phải vấn đề này trong thực tế khá thường xuyên. Ví dụ: sử dụng gói reshape của hadley:

> 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

Được rồi, nhưng tại sao bạn cần thay thế các tên hợp lệ về mặt cú pháp (như x hoặc y) bằng những tên không hợp lệ (như 1 hoặc 2) yêu cầu dấu gạch ngược?
Dirk Eddelbuettel

3
Nó cũng hữu ích read.tablekhi check.nameslà false - tức là khi bạn muốn làm việc với các tên cột ban đầu.
hadley 24-08-09

25

Không biết điều này được / không được nhiều người biết đến như thế nào, nhưng một thứ mà tôi chắc chắn đã tận dụng là khả năng tham chiếu qua lại của các môi trường.

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

Đối với ví dụ này, không hiểu tại sao nó lại hữu ích, nhưng nếu bạn chuyển các vật thể lớn xung quanh thì nó có thể hữu ích.


23

Điều yêu thích mới của tôi là thư viện foreach. Nó cho phép bạn làm tất cả những điều tốt đẹp áp dụng, nhưng với một cú pháp dễ dàng hơn một chút:

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

Phần tốt nhất là nếu bạn đang làm điều gì đó thực sự đòi hỏi một lượng thời gian đáng kể, bạn có thể chuyển từ %do%sang %dopar%(với thư viện phụ trợ thích hợp) để song song ngay lập tức, thậm chí trên một cụm. Rất bóng bẩy.


19

Tôi thực hiện rất nhiều thao tác cơ bản với dữ liệu, vì vậy đây là hai hàm tích hợp ( biến đổi , tập hợp con ) và một thư viện ( sqldf ) mà tôi sử dụng hàng ngày.

tạo dữ liệu bán hàng mẫu

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

sử dụng biến đổi () để thêm một cột

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

sử dụng tập con () để cắt dữ liệu

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

>
  product  revenue
1       1 108.4597
4       2 100.3475

sử dụng sqldf () để cắt và tổng hợp với SQL

Các gói sqldf cung cấp một giao diện SQL để khung dữ liệu 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

Thực hiện tổng hợp hoặc 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

Để có chức năng giống như giảm bản đồ phức tạp hơn trên khung dữ liệu, hãy xem gói plyr . Và nếu thấy mình muốn kéo tóc của bạn ra, tôi khuyên bạn nên kiểm tra ra Thao tác dữ liệu với R .


18
?ave

Các tập con của 'x []' được tính trung bình, trong đó mỗi tập con bao gồm những quan sát có cùng mức yếu tố. Cách sử dụng: ave (x, ..., FUN = mean)

Tôi sử dụng nó mọi lúc. (ví dụ: trong câu trả lời này tại đây )


Điều này khác với tapply (x, factor, fun) như thế nào ??
TMS

1
@Tomas ave giữ nguyên thứ tự và độ dài. vì vậy, bạn có thể, ví dụ, thêm một vectơ của nhóm phương tiện vào tập dữ liệu, trong một bước.
Eduardo Leoni

18

Một cách để tăng tốc mã và loại bỏ vòng lặp for.

thay vì vòng lặp for lặp qua khung dữ liệu để tìm kiếm giá trị. chỉ cần lấy một tập hợp con của df với các giá trị đó, nhanh hơn nhiều.

vì vậy thay vì:

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

làm một cái gì đó như thế này:

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

khái niệm cơ sở đó được áp dụng rất thường xuyên và là một cách tuyệt vời để loại bỏ các vòng lặp for


11
Có một cái bẫy nhỏ ở đây thường bắt tôi. Nếu df $ column1 chứa các giá trị NA, việc đặt con bằng cách sử dụng == sẽ lấy ra bất kỳ giá trị nào bằng x bất kỳ NA nào. Để tránh điều này, hãy sử dụng "% in%" thay vì "==".
Matt Parker

Matt bạn hoàn toàn đúng và đó là điều tôi ghét, tôi thích phương pháp của bạn. Tôi thường kiểm tra cột để tìm NA và sau đó xóa chúng bằng một chức năng nhanh mà tôi đã thực hiện lấy một cột khung dữ liệu và trả về khung dữ liệu trừ các hàng có NA trong chỉ cột đó.
Dan

về cơ bản, tôi chia một khung dữ liệu xuống các cột tôi cần có giá trị, sau đó sử dụng na.omit để lấy các hàng chính xác và sau đó đặt con tập dữ liệu ban đầu chỉ với các hàng đó. Chỉ cần sử dụng na.omit sẽ loại bỏ bất kỳ hàng nào với bất kỳ NA nào, mặc dù vậy tôi có thể bị nhầm.
Dan

16

Đôi khi bạn cần rbindnhiều khung dữ liệu. do.call()sẽ cho phép bạn làm điều đó (ai đó đã phải giải thích điều này cho tôi khi ràng buộc tôi đã hỏi câu hỏi này, vì nó có vẻ không phải là một công dụng rõ ràng).

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)

Cuộc gọi tốt: Tôi thấy rằng điều này thường đơn giản hơn so với việc sử dụng unsplit.
Richie Cotton

16

Trong lập trình R (không phiên tương tác), tôi sử dụng if (bad.condition) stop("message")một nhiều . Mọi hàm đều bắt đầu với một vài trong số này, và khi tôi làm việc thông qua các phép tính, tôi cũng sử dụng chúng. Tôi đoán tôi đã có thói quen từ việc sử dụng assert()ở C. Lợi ích gấp đôi. Đầu tiên, nhanh hơn rất nhiều để có được mã làm việc với các kiểm tra này tại chỗ. Thứ hai, và có lẽ quan trọng hơn, việc làm việc với mã hiện có sẽ dễ dàng hơn rất nhiều khi bạn nhìn thấy những dấu kiểm này trên mọi màn hình trong trình soạn thảo của mình. Bạn sẽ không phải băn khoăn x>0hay tin tưởng vào một nhận xét nói rằng đó là ... chỉ cần nhìn thoáng qua, bạn sẽ biết nó là như vậy.

Tái bút. bài viết đầu tiên của tôi ở đây. Hãy nhẹ nhàng!


12
Không phải là một thói quen xấu, và R đưa ra một cách khác: stopfifnot(!bad.condition)ngắn gọn hơn.
Dirk Eddelbuettel

13

Các traceback()chức năng là điều bắt buộc khi bạn có một đâu đó lỗi và không hiểu nó dễ dàng. Nó sẽ in ra một dấu vết của ngăn xếp, rất hữu ích vì R không dài dòng theo mặc định.

Sau đó, cài đặt options(error=recover)sẽ cho phép bạn "nhập" vào chức năng nâng cao lỗi và thử và hiểu chính xác điều gì sẽ xảy ra, như thể bạn có toàn quyền kiểm soát nó và có thể đưa browser()nó vào.

Ba chức năng này thực sự có thể giúp gỡ lỗi mã của bạn.


1
options(error=recover)là phương pháp gỡ lỗi yêu thích của tôi.
Joshua Ulrich

12

Tôi thực sự ngạc nhiên khi chưa có ai đăng về apply, tapply, lapply và sapply. Một quy tắc chung mà tôi sử dụng khi thực hiện nội dung trong R là nếu tôi có vòng lặp for đang thực hiện xử lý hoặc mô phỏng dữ liệu, tôi cố gắng loại bỏ nó và thay thế nó bằng dấu * áp dụng. Một số người né tránh các hàm * apply vì họ nghĩ rằng chỉ có thể truyền các hàm tham số đơn lẻ vào. Giống như truyền xung quanh các hàm có tham số là đối tượng lớp đầu tiên trong Javascript, bạn thực hiện điều này trong R với các hàm ẩn danh. Ví dụ:

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

(Đối với những người theo dõi #rstats, tôi cũng đăng điều này ở đó).

Hãy nhớ, sử dụng apply, sapply, lapply, tapply và do.call! Lấy vectơ hóa của R. Bạn không bao giờ nên đi đến một đống mã R và xem:

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

Điều này không chỉ không được vector hóa, mà cấu trúc mảng trong R không được phát triển như trong Python (tăng gấp đôi kích thước khi hết dung lượng, IIRC). Vì vậy, mỗi bước rbind đầu tiên phải phát triển l đủ để chấp nhận kết quả từ rbind (), sau đó sao chép tất cả nội dung của l trước đó. Để giải trí, hãy thử cách trên trong R. Hãy để ý xem mất bao lâu (thậm chí bạn sẽ không cần Rprof hoặc bất kỳ chức năng định thời nào). Vậy hãy thử đi

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

Phiên bản sau cũng tốt hơn phiên bản đầu tiên:

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

apply, sapply, lapply và tapply đều hữu ích. Nếu bạn muốn truyền các tham số cho một hàm được đặt tên như round, bạn chỉ có thể chuyển nó cùng với apply thay vì viết một hàm ẩn danh. Hãy thử "sapply (rnorm (10, 0, 1), vòng, chữ số = 2)" cho kết quả "[1] -0,29 0,29 1,31 -0,06 -1,90 -0,84 0,21 0,02 0,23 -1,10".
Daniel

11

Theo lời khuyên của Dirk, tôi đăng các ví dụ đơn lẻ. Tôi hy vọng họ không quá "dễ thương" [thông minh, nhưng tôi không quan tâm] hoặc tầm thường đối với khán giả này.

Mô hình tuyến tính là bánh mì và bơ của R. Khi số lượng biến độc lập nhiều, người ta có hai lựa chọn. Đầu tiên là nó sử dụng lm.fit (), nhận ma trận thiết kế x và phản hồi y làm đối số, tương tự như Matlab. Hạn chế của cách tiếp cận này là giá trị trả về là danh sách các đối tượng (hệ số phù hợp, phần dư, v.v.), không phải đối tượng của lớp "lm", có thể được tóm tắt độc đáo, được sử dụng để dự đoán, lựa chọn từng bước, v.v. Thứ hai cách tiếp cận là tạo một công thức:

> 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  

Còn nếu bạn chọn một cái cho mỗi bài đăng và minh họa bằng một ví dụ? Sau đó, chúng tôi có thể tiếp tục trong nhiều ngày liên tục và đăng các ví dụ mới với các lệnh mới ... [BTW: Theo tôi nhớ lại, bạn cần as.formula (paste (...)) để sử dụng công thức. ]
Dirk Eddelbuettel

Bạn không cần tạo công thức rõ ràng để bao gồm tất cả các cột vì biểu mẫu "y ~. - 1" bao gồm nó. Các "." có nghĩa là 'tất cả các cột ngoại trừ biến phụ thuộc và' - 1 'loại trừ hằng số như trong ví dụ của bạn.
Dirk Eddelbuettel

Điều đó đúng với ví dụ cụ thể này, nhưng đối với X với ncols >> nrows, tôi thường loại bỏ một số biến độc lập, đặc biệt là trong giai đoạn cuối của phân tích. Trong trường hợp này, việc tạo công thức từ tên khung dữ liệu vẫn hữu ích.
gappy

10

Bạn có thể chỉ định một giá trị trả về từ một khối if-else.

Thay vì, ví dụ

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

bạn có thể làm

x <- if(condition) 1 else 2

Chính xác cách thức hoạt động của nó là phép thuật sâu sắc.


6
Bạn cũng có thể làm điều này như x <- ifelse (điều kiện, 1, 2), trong trường hợp này mỗi thành phần được vector hóa.
Shane

Shane, bạn có thể, nhưng trừ khi bạn thực sự tìm hiểu sâu những gì ifelse () làm, bạn có thể không nên! Đó là một điều dễ dàng để hiểu sai ...
Harlan

Điều gì là huyền diệu về điều đó? Đó chỉ là cách các if-then-elsebiểu thức hoạt động trong bất kỳ ngôn ngữ chức năng nào (đừng nhầm lẫn với các if-then-else câu lệnh ). Rất giống với toán ?:tử bậc ba của các ngôn ngữ giống C.
Frank

10

Là một người hoàn toàn mới đến R và là một người mới làm quen với các chỉ số mà tôi yêu thích unclass() in tất cả các phần tử của khung dữ liệu như một danh sách bình thường.

Nó khá tiện lợi để xem toàn bộ tập dữ liệu trong một lượt để nhanh chóng kiểm tra mọi vấn đề tiềm ẩn.


9

CrossTable()từ gmodelsgói này cung cấp khả năng truy cập dễ dàng vào các bảng chéo kiểu SAS và SPSS, cùng với các bài kiểm tra thông thường (Chisq, McNemar, v.v.). Về cơ bản, nó xtabs()có đầu ra ưa thích và một số thử nghiệm bổ sung - nhưng nó giúp việc chia sẻ đầu ra với những người ngoại đạo dễ dàng hơn.


Đẹp!! Tôi sử dụng gmodels khá một chút, nhưng nhỡ mà một
Abhijit

Câu trả lời hay, bất cứ điều gì có thể giúp tôi tránh xa những lời giải thích quá mức về những cuộc bàn tán với người ngoại đạo là sử dụng thời gian tốt.
Stedy

7

Chắc chắn system(). Để có thể truy cập vào tất cả các công cụ unix (ít nhất là trong Linux / MacOSX) từ bên trong môi trường R đã nhanh chóng trở nên vô giá trong quy trình làm việc hàng ngày của tôi.


1
Điều đó liên quan đến nhận xét trước đây của tôi về các kết nối: bạn cũng có thể sử dụng pipe () để truyền dữ liệu từ hoặc đến các lệnh Unix. Xem help(connections)chi tiết và ví dụ.
Dirk Eddelbuettel

6

Đây là một cách giải quyết khó chịu để chuyển đổi một thừa số thành một số. (Tương tự cho các kiểu dữ liệu khác)

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

2
Có thể ý bạn là "thành một chiếc xe ngựa". Trong trường hợp "as.character (old.var)" thì đơn giản hơn.
Dirk Eddelbuettel

1
Tôi luôn nghĩ rằng lời khuyên này (có thể đọc tại? Factor) là sai lầm. Bạn phải chắc chắn old.var là một yếu tố và điều này sẽ thay đổi tùy theo các tùy chọn bạn đặt cho phiên R. Sử dụng as.numeric (as.character (old.var)) an toàn hơn và sạch hơn.
Eduardo Leoni

Thực sự không đáng để một lời tán thành, nhưng bất cứ điều gì. Điều này làm việc cho tôi.
Ryan R. Rosario

Ryan - Bạn có thể sửa mã của mình không? If old.var <- factor (1: 2); mã của bạn sẽ cung cấp cho [1] "1" "2" (không phải số.) Có lẽ bạn muốn nói là as.numeric (các cấp (old.var) [old.var])?
Eduardo Leoni

3
Hoặc hiệu quả hơn một chút:as.numeric(levels(old.var))[old.var]
hadley 20-08-09

6

Mặc dù câu hỏi này đã được đặt ra trong một thời gian gần đây tôi đã phát hiện ra một thủ thuật tuyệt vời trên blog SAS và R để sử dụng lệnh cut. Lệnh được sử dụng để chia dữ liệu thành các danh mục và tôi sẽ sử dụng tập dữ liệu mống mắt làm ví dụ và chia nó thành 10 danh mục:

> 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

Một thủ thuật khác. Một số gói, như glmnet, chỉ lấy đầu vào là ma trận thiết kế và biến phản hồi. Nếu một người muốn phù hợp với một mô hình có tất cả các tương tác giữa các đối tượng địa lý, người đó không thể sử dụng công thức "y ~. ^ 2". Việc sử dụng expand.grid()cho phép chúng ta tận dụng các hoạt động lập chỉ mục mảng và vectơ mạnh mẽ của 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
Nếu một hàm mô hình hóa không chấp nhận một công thức (điều này rất hiếm xảy ra!) Thì sẽ tốt hơn nếu xây dựng ma trận thiết kế với model.matrix?
hadley

Tốt lắm. Tôi không biết về sự tồn tại của chức năng này. Hàm trên tương đương với model.matrix (~. ^ 2 -1, X) Nhưng liên quan đến việc truyền ma trận, ngoài glmnet, tôi thường xuyên truyền con trỏ mảng cho các hàm C tùy chỉnh. Thật vậy, tôi sẽ không biết cách chuyển một công thức cho một hàm. Bạn có một ví dụ về đồ chơi?
gappy

5

Một trong những thủ thuật yêu thích của tôi, nếu không muốn nói là hơi không chính thống, là việc sử dụng eval()parse(). Ví dụ này có thể minh họa cách nó có thể hữu ích

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

[1] "Albany"

Loại tình huống này xảy ra thường xuyên hơn không, và việc sử dụng eval()parse()có thể giúp giải quyết nó. Tất nhiên, tôi hoan nghênh bất kỳ phản hồi nào về các cách khác để mã hóa điều này.


1
Điều này cũng có thể được thực hiện với các phần tử vector được đặt tên.
Dirk Eddelbuettel

3
thư viện (vận may); tài sản (106) Nếu câu trả lời là phân tích cú pháp (), bạn thường nên suy nghĩ lại câu hỏi. - Thomas Lumley R-help (tháng 2 năm 2005)
Eduardo Leoni

Đây là một ví dụ mà eval () và parse () có thể hữu ích. Điều này liên quan đến gói Bioconductor, ví dụ: hgu133a.db và nơi bạn đang cố gắng lấy các phần thông tin khác nhau về id tập hợp đầu dò. Ví dụ: tham số library (hgu133a.db) <- 'SYMBOL' mget ('202431_s_at', env = eval (parse (text = paste ('hgu133a', parameter, sep = '')))) tham số <- 'ENTREZID 'mget (' 202431_s_at', env = eval (parse (text = dán ( 'hgu133a', tham số, tháng chín = ''))))
andrewj

Như Dirk nói, điều này được tốt hơn thực hiện với các yếu tố vector được đặt tên, hoặc `get` (dán (nhà nước, tham số, tháng chín =) '')
hadley

@Hadley, không biết rằng bạn có thể sử dụng get () theo cách đó. Cảm ơn.
andrewj

5

set.seed() đặt trạng thái tạo số ngẫu nhiên.

Ví dụ:

> set.seed(123)
> rnorm(1)
[1] -0.5604756
> rnorm(1)
[1] -0.2301775
> set.seed(123)
> rnorm(1)
[1] -0.5604756

siêu hữu ích với các ví dụ sử dụng chức năng ngẫu nhiên ... giúp get tất cả mọi người trên cùng một trang
JD dài

5

Đối với những người đang viết C để được gọi từ R: .Internal(inspect(...))rất tiện lợi. Ví dụ:

> .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 Mã / Thư viện /'

files = list.files (d, '. r $')

for (f in files) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}

Tôi sử dụng đoạn mã trên để tạo nguồn tất cả các tệp trong một thư mục khi khởi động với các chương trình tiện ích khác nhau mà tôi sử dụng trong phiên tương tác của mình với R. Tôi chắc chắn có nhiều cách tốt hơn nhưng tôi thấy nó hữu ích cho công việc của mình. Dòng thực hiện điều này như sau.

source ("~ / R Code / Library / mysource.r")


6
Đừng làm vậy. Viết một gói.
Dirk Eddelbuettel

Cảm ơn. Tôi đã xem xét một hoặc hai luồng trên roxygen và có vẻ như tôi có lẽ đang ở mức mà tôi nên thử viết một gói tự sử dụng đơn giản.
mcheema

3

Để thực hiện thao tác trên một số biến trong khung dữ liệu. Điều này bị đánh cắp từ 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
Điều này thoạt nghe có vẻ thú vị, nhưng loại mã này sẽ khiến bạn không gặp rắc rối về lâu dài. Luôn luôn tốt hơn là rõ ràng.
hadley

hum nay, tôi đã sử dụng thủ thuật này khá lâu rồi. Bạn có thể nói rõ hơn về rắc rối không giới hạn của nó?
Ian Fellows

Có lẽ hadley đang đề nghị sử dụng gói plyr thay thế?
Christopher DuBois

3
Không, đây không phải là một gợi ý được che đậy để sử dụng plyr thay thế. Vấn đề cơ bản với mã của bạn là nó khá lười về mặt ngữ nghĩa - thay vì khiến người dùng phải đánh vần rõ ràng những gì họ muốn, bạn thực hiện một số "phép thuật" để đoán. Vấn đề với điều này là nó làm cho hàm rất khó lập trình - tức là rất khó để viết một hàm gọi get.varsmà không cần chuyển qua nhiều vòng lặp.
hadley 23/08/09

3

Tôi đã đăng bài này một lần trước đây nhưng tôi sử dụng nó quá nhiều nên tôi nghĩ rằng tôi sẽ đăng lại. Nó chỉ là một chức năng nhỏ để trả về tên và số vị trí của data.frame. Nó không có gì đặc biệt để chắc chắn, nhưng tôi hầu như không bao giờ vượt qua một phiên mà không sử dụng nó nhiều lần.

##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 <- tên


4
Đây là một thực sự là một one-liner:data.frame(VAR = names(df), COL = seq_along(df))
hadley

rất thanh lịch, có lẽ tôi sẽ chuyển nó thành ni <- function (df) {data.frame (VAR = names (df), COL = seq_along (df))}
kpierce

1
Tôi sử dụng: data.frame (colnames (the.df))
Tal Galili
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.