가장 유용한 R 트릭은 무엇입니까? [닫은]


88

R 에 대한 더 많은 팁과 트릭을 공유하기 위해 가장 유용한 기능 또는 트릭은 무엇입니까? 영리한 벡터화? 데이터 입 / 출력? 시각화와 그래픽? 통계 분석? 특수 기능? 대화 형 환경 자체?

게시물 당 하나의 항목이며, 투표를 통해 우승자를 얻을 수 있는지 확인합니다.

[2008 년 8 월 25 일 편집] : 1 주일 후에 단순 str()이 투표에서이긴 것 같습니다 . 내가 직접 추천하고 싶기 때문에 받아들이 기 쉬운 대답입니다.


8
@Dirk : "커뮤니티 위키"는 "커뮤니티 소유"를 의미하며 "설문 조사 질문"의 동의어가 아닙니다. 커뮤니티 위키 경찰의 말을 듣지 마십시오.
Juliet


8
CW가 또 괴롭힘. 당신의 meta-SO를보고 당신을 올릴 것입니다 : meta.stackexchange.com/questions/392/…
ars

13
@ars : 명확한 답변이없는 질문입니다 . Ergo는 CW로 만듭니다.
dmckee --- 전 사회자 고양이

2
@JD 긴 유쾌한 코멘트. 안타깝게도 접힌 부분 뒤에 숨겨져있었습니다. 어려운 R 질문에 답하는 것은 실제로 스택 담당자에게 현명한 비용을 지불하지 않는다는 것을 의미합니다. 따라서 R을지도에 표시하는 멋진 질문을 설정 한 사람들이 마침내 약간의 공로를 인정해도 괜찮습니다. 게다가 이것은 C 프로그래머에게 가장 좋아하는 C 트릭 질문보다 R 사용자에게 확실히 더 유용합니다 ...
Matt Bannert

답변:


64

str() 모든 물체의 구조를 알려줍니다.


파이썬 사용 dir()-더 의미가 있습니다.
Hamish Grubijan

17
아, str또한 string여러 언어의 약자입니다 .
Hamish Grubijan

왜 안돼 class()? 비슷한 유형의 정보가 드러나는 것 같습니다. 두 가지 유사한 명령이있는 이유는 무엇입니까?
hhh apr

1
class()str()표시 되는 정보의 일부일뿐입니다
hadley 2011

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 (의사 난수 생성기가 아닌 대기 소음을 기반으로 실제 난수를 제공) 에서 최소 = 100에서 최대 = 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 액세스를위한 몇 가지 편리한 기능을 제공합니다 .


BTW-- 난 당신이 제안 거라고 해야 당신이 즉시 그들을 게시 및 (2) 질문 CW하지 않는다 (1) 경우 selfanswers CW합니다. 그렇지 않으면 rep 시스템을 게임하려는 것처럼 보입니다. YMMV 및 모든 것.
dmckee --- 전 중재자 새끼 고양이

1
시스템을 게임하는 것이 아니라 단지 시작하는 것입니다. 그는 여전히 다른 대답을 자유롭게 받아 들일 수 있습니다.
ars

2
@ars : 그는 이것을 받아 들일 자유가 있습니다. 나는 그가 내 조언을 받아들이지 않는다면 그에게 위키를 강요하지 않을 것이다. 그러나 나는 그것을 위키로 표시하지 않고 준비된 자체 답변을 게시하지 않을 것이며 그것 없이는 하나에 투표하지 않을 것입니다. 그 가치를 위해 가져 가십시오.
dmckee --- 전 사회자 고양이

4
@Dirk : Jeff와 Joel이 귀하의 질문에 답하는 것도 전적으로 받아 들일 수 있습니다. 귀하의 답변을 CW로 작성하는 데 비공식적조차도 요구 사항은 없습니다. 당신은 분명히 시스템 게임이 아닙니다. 다시 한 번 커뮤니티 위키 경찰을 무시하십시오.
Juliet

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 Forms를 사용하면 응답자의 데이터를 캡처하여 손쉽게 Google 스프레드 시트에 작성할 수 있습니다. 데이터가 자주 변경되고 거의 최종적이지 않기 때문에 R이 csv 파일을 다운로드하고 읽는 것보다 Google 스프레드 시트를 직접 읽는 것이 훨씬 바람직합니다.

# 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  

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

좋아, 그런데 구문 상 유효한 이름 (예 : x 또는 y)을 백틱이 필요한 유효하지 않은 이름 (예 : 1 또는 2)으로 바꿔야합니까?
Dirk Eddelbuettel

3
또한 false 인 경우 (예 : 원래 열 이름으로 작업하려는 read.table경우 check.names) 에도 유용 합니다.
hadley 2009-08-24

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

저는 기본적인 데이터 조작을 많이하므로 매일 사용하는 두 개의 내장 함수 ( 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 ()을 사용하여 열 추가

## 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 ()를 사용하여 SQL로 슬라이스 및 집계

sqldf 패키지는 R 데이터 프레임에 대한 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

집계 또는 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

데이터 프레임에 대한보다 정교한 맵 축소 기능에 대해서는 plyr 패키지를 확인하십시오 . 머리카락을 꺼내고 싶다면 R을 사용한 데이터 조작을 확인하는 것이 좋습니다 .


18
?ave

'x []'의 부분 집합은 평균을 내며 각 부분 집합은 요인 수준이 동일한 관측치로 구성됩니다. 사용법 : ave (x, ..., FUN = mean)

나는 항상 그것을 사용합니다. (예 : 여기 에이 답변에서 )


이것이 tapply (x, factor, fun)과 어떻게 다른가요?
TMS

1
@Tomas ave는 순서와 길이를 유지합니다. 예를 들어 그룹 평균의 벡터를 데이터 세트에 한 번에 추가 할 수 있습니다.
Eduardo Leoni

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 %"를 사용하십시오.
Matt Parker

Matt 당신이 절대적으로 옳고 그것은 내가 싫어하는 것입니다. 나는 당신의 방법을 좋아합니다. 나는 일반적으로 열에서 NA를 확인한 다음 데이터 프레임 열을 가져와 해당 열에 만 NA가있는 행을 뺀 데이터 프레임을 반환하는 빠른 함수로 제거합니다.
Dan

기본적으로 데이터 프레임을 값이 필요한 열로 축소 한 다음 na.omit을 사용하여 올바른 행을 가져온 다음 해당 행만있는 원래 데이터 세트의 하위 집합을 만듭니다. na.omit을 사용하면 NA가있는 모든 행이 제거되지만 착각 할 수 있습니다.
Dan

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 프로그래밍 (안 대화 형 세션), 나는 사용 많이 . 모든 함수는 이들 중 몇 개로 시작하며, 계산을 진행하면서 이것도 추가합니다. 나는 C 에서 사용하면서 습관 이 된 것 같습니다. 이점은 두 가지입니다. 첫째, 이러한 검사를 통해 작업 코드를 얻는 것이 훨씬 빠릅니다. 둘째, 아마도 더 중요한 것은 편집기의 모든 화면에서 이러한 검사를 볼 때 기존 코드로 작업하는 것이 훨씬 쉽다는 것입니다. 당신은 경이 여부가 없습니다 , 또는 댓글 당신은거야 ... 그것이 없다는 신뢰 알고 는 것을 한 눈에서.if (bad.condition) stop("message")assert()x>0

추신. 여기에 내 첫 번째 게시물. 부드럽게!


12
나쁜 습관은 아니며 R은 또 다른 방법을 제공합니다 stopfifnot(!bad.condition).
Dirk Eddelbuettel 2010 년

13

traceback()오류의 어딘가를 쉽게 이해하지 않는 경우 기능은 필수입니다. R은 기본적으로 매우 장황하지 않기 때문에 스택의 추적을 인쇄합니다.

그런 다음 설정 options(error=recover)을 통해 오류를 발생시키는 함수에 "입력"하고 마치 완전히 제어 할 수 있고 오류를 넣을 수있는 것처럼 정확히 어떤 일이 발생하는지 파악할 수 browser()있습니다.

이 세 가지 함수는 코드 디버깅에 실제로 도움이 될 수 있습니다.


1
options(error=recover)제가 가장 좋아하는 디버깅 방법입니다.
Joshua Ulrich

12

신청, 탭 플라이, 라 플라이, sapply에 대해 게시 한 사람이 아무도 없다는 사실에 정말 놀랐습니다. R에서 작업을 수행 할 때 사용하는 일반적인 규칙은 데이터 처리 또는 시뮬레이션을 수행하는 for 루프가있는 경우이를 제외하고 * apply로 대체하려고한다는 것입니다. 일부 사람들은 단일 매개 변수 함수 만 전달할 수 있다고 생각하기 때문에 * apply 함수를 피합니다. 진실에서 더 멀어 질 수있는 것은 없습니다! 자바 스크립트에서 첫 번째 클래스 객체로 매개 변수가있는 함수를 전달하는 것과 같이 익명 함수를 사용하여 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 단계는 먼저 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와 함께 전달하면됩니다. "[1] -0.29 0.29 1.31 -0.06 -1.90 -0.84 0.21 0.02 0.23 -1.10"을 출력하는 "sapply (rnorm (10, 0, 1), round, numbers = 2)"를 시도합니다.
Daniel

11

Dirk의 조언에 따라 단일 예제를 게시하고 있습니다. 나는 그들이이 청중들에게 너무 "귀엽거나"[영리하지만 나는 상관하지 않는다]거나 사소하지 않기를 바랍니다.

선형 모델은 R의 기본입니다. 독립 변수의 수가 많으면 하나는 두 가지 선택을 할 수 있습니다. 첫 번째는 Matlab과 유사하게 디자인 행렬 x와 응답 y를 인수로받는 lm.fit ()을 사용하는 것입니다. 이 접근 방식의 단점은 반환 값이 "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  

게시물 당 하나를 선택하고 예를 들어 설명하면 어떨까요? 그런 다음 며칠 동안 계속해서 새 명령을 사용하여 새 예제를 게시 할 수 있습니다 ... [BTW : 제가 기억하는 것처럼 수식 사용을 위해서는 as.formula (paste (...))가 필요합니다. ]
Dirk Eddelbuettel

"y ~.-1"형식이 모든 열을 다루기 때문에 명시 적으로 수식을 생성 할 필요가 없습니다. "." '종속 변수를 제외한 모든 열'을 의미하고 '-1'은 예제에서와 같이 상수를 제외합니다.
Dirk Eddelbuettel

이 특정 예제에는 맞지만 ncols >> nrows가있는 X의 경우, 특히 분석의 마지막 단계에서 일부 독립 변수를 제거하는 경우가 많습니다. 이 경우에도 데이터 프레임 이름에서 수식을 만드는 것이 여전히 편리합니다.
gappy

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

그것에 대해 마법은 무엇입니까? 이는 if-then-else모든 기능적 언어에서 표현식이 작동 하는 방식 입니다 ( if-then-else 문과 혼동하지 마십시오 ). ?:C와 유사한 언어 의 삼항 연산자 와 매우 유사합니다 .
Frank

10

R에 대한 완전한 멍청이이자 내가 좋아하는 통계의 초보자로서 unclass() 데이터 프레임의 모든 요소를 ​​일반 목록으로 인쇄하는 합니다.

잠재적 인 문제를 빠르게 파악하기 위해 한 번에 전체 데이터 세트를 살펴 보는 것은 매우 편리합니다.


9

CrossTable()로부터 gmodels패키지 일반적인 테스트 (Chisq, McNemar 등)과 함께 SAS- 및 SPSS 스타일의 교차 분석에 쉽게 액세스를 제공합니다. 기본적으로 xtabs()멋진 출력과 몇 가지 추가 테스트가 있지만 이교도들과 출력을 더 쉽게 공유 할 수 있습니다.


좋은!! 내가 사용은 상당히 gmodels 였으나 놓친 하나
Abhijit

좋은 대답, 이교도들과 함께 테이블에 대한 과도한 설명을 피할 수있는 것은 무엇이든 시간을 잘 활용하는 것입니다.
Stedy 2010-04-27

7

확실히 system(). R 환경 내부에서 모든 유닉스 도구 (적어도 Linux / MacOSX에서)에 액세스 할 수 있다는 것은 일상적인 워크 플로에서 빠르게 귀중한 일이되었습니다.


1
이는 연결에 대한 이전 의견과 관련이 있습니다. pipe ()를 사용하여 Unix 명령에서 데이터를 전달하거나 전달할 수도 있습니다. 자세한 help(connections)내용과 예는를 참조하십시오 .
Dirk Eddelbuettel

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))을 사용하는 것이 더 안전하고 깨끗합니다.
Eduardo Leoni

비추천할만한 가치는 없지만 뭐든지 요. 이것은 나를 위해 작동합니다.
Ryan R. Rosario

Ryan-코드를 고칠 수 있습니까? 만약 old.var <-factor (1 : 2); 귀하의 코드는 [1] "1" "2"(숫자가 아님)를 제공합니다. 아마도 as.numeric (levels (old.var) [old.var])을 의미했을까요?
Eduardo Leoni

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 2009-08-19

멋지네요. 나는이 기능의 존재를 몰랐다. 위의 함수는 model.matrix (~. ^ 2 -1, X)와 동일합니다. 그러나 행렬 전달과 관련하여 glmnet 외에 배열 포인터를 사용자 지정 C 함수에 전달하는 경우가 자주 있습니다. 실제로 함수에 수식을 전달하는 방법을 모르겠습니다. 장난감 예가 있습니까?
gappy

5

다소 비 정통적인 트릭은 아니지만 제가 가장 좋아하는 트릭 중 하나는 eval()parse(). 이 예는 도움이 될 수있는 방법을 보여줍니다.

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

[1] "Albany"

이러한 상황은 못하는 것보다 더 자주 발생하며, 사용 eval()parse()캔 도움 주소입니다. 물론 이것을 코딩하는 다른 방법에 대한 피드백을 환영합니다.


1
이것은 명명 된 벡터 요소로도 수행 할 수 있습니다.
Dirk Eddelbuettel

3
library (fortunes); fortune (106) 대답이 parse ()이면 일반적으로 질문을 다시 생각해야합니다. -Thomas Lumley R-help (2005 년 2 월)
Eduardo Leoni

다음은 eval () 및 parse ()가 유용 할 수있는 예입니다. 여기에는 Bioconductor 패키지 (예 : hgu133a.db)가 포함되며 여기에서 probeset ID에 대한 다양한 정보를 얻으려고합니다. 예 : library (hgu133a.db) parameter <- 'SYMBOL'mget ( '202431_s_at', env = eval (parse (text = paste ( 'hgu133a', parameter, sep = '')))) parameter <- '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

set.seed() 난수 생성기 상태를 설정합니다.

예를 들면 :

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

슈퍼 유용한 임의 함수를 사용하여 예제와 함께 ... 같은 페이지에 엎드려 모두를하는 데 도움이
JD 롱

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 $')

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

위의 코드를 사용하여 R과의 대화식 세션에서 사용하는 다양한 유틸리티 프로그램을 시작할 때 디렉토리의 모든 파일을 소싱합니다. 더 좋은 방법이 있지만 내 작업에 유용하다고 생각합니다. 이를 수행하는 라인은 다음과 같습니다.

source ( "~ / R 코드 / 라이브러리 /mysource.r")


6
하지마. 패키지를 작성하십시오.
Dirk Eddelbuettel 2010

감사. 나는 roxygen에 대한 실을 한두 개 살펴 보았고 아마도 간단한 자체 사용 패키지를 작성해야 할 수준에있는 것 같습니다.
mcheema 2010

3

데이터 프레임의 여러 변수에 대해 작업을 수행합니다. 하위 집합 .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

콧노래, 나는 최근에이 트릭을 꽤 많이 사용하고있다. 무한한 문제에 대해 더 구체적으로 말씀해 주시겠습니까?
Ian Fellows

아마도 hadley가 대신 plyr 패키지를 사용하도록 제안하고 있습니까?
Christopher DuBois

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

매우 우아합니다. ni <-function (df) {data.frame (VAR = names (df), COL = seq_along (df))}
kpierce8

1
나는 사용 : data.frame (colnames (the.df))
Tal Galili
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.