close
Lesson1裡用了一個小例子來說R使用者常遇到的困擾:
> colMeans(iris)
Error in colMeans(iris) : 'x' must be numeric
如果對物件結構不清楚,會很容易出現一直出現Error!所以常常要查物件結構。
另一個必須了解結構的理由,是為了對付複雜的list。雖然一般人很少從list(列表)開始處理,但是函數做分析後的輸出,得到的結果很可能是一堆東西堆疊成的list,我們總免不了要自己去list裡面抓一些東西出來用。看個例子吧:
這邊用迴歸分析(Regression)的輸出結果做例子:對數這筆資料,用體積Volume和樹圍Girth跑迴歸分析配出一條線。
> (fit <- lm(Volume ~ Girth, data=trees))
Call:
lm(formula = Volume ~ Girth, data = trees)
Coefficients:
(Intercept) Girth
-36.943 5.066
這裡不討論迴歸的觀念,只是拿它做例子看看一個函數的output可以有多雜亂。
雖然上面印出的東西看起來簡單(截距和斜率估出來了),但是如果你稍微知道迴歸或linear model,應該會奇怪這個output怎麼這樣就沒了....
分析結果當然不只這樣,就是因為有太多東西輸出了,不應該隨便印出來,所以作者把很多東西藏起來了,只讓你看最簡單的東西。這種輸出方式,也是R和其他統計軟體最大的差別:他跑出結果只會印出最少量的資訊,剩下的等著有須要的人從輸出結果的物件中截取。而且,作者們為了方便使用者,會再寫一些函數來方便使用者提取重要的結果。至於如何知道有什麼函數能幫助截取重要內容呢?進入?lm裡,直接拉到最下面的example的例子裡,搭配截取報表的函數一定放在這裡給你看。
做為一個使用者,要在R裡暢行無阻,可以說help()和str()分別管了半壁江山。要了解函數lm()要靠help(),但要了解各種物件或分析結果取東西要靠str()。關於更多help的介紹,請看Lesson4 教你如何從help裡自學R和統計。先看結構的部份:
str()的功能是完整顯示R裡面所有物件的結構,Compactly display the internal structure of an R object。很多時候資料太大、我們不能印出完整資料來看(而且也沒有意義),甚至看頭看尾的函數head() tail()也不會有太大幫助。只有str()能幫你。
請自己在R裡用str()看物件完整的組成訊息,因為內容實在太多太浪費版面了,我只有留了一部份輸出結果。一開始str就寫了:這是12個項目組成的list。然後開始往下列每一項的結構。
> str(fit)
List of 12
$ coefficients : Named num [1:2] -36.94 5.07
$ coefficients : Named num [1:2] -36.94 5.07
..- attr(*, "names")= chr [1:2] "(Intercept)" "Girth"
(中間...略)
$ model :'data.frame': 31 obs. of 2 variables:
..$ Volume: num [1:31] 10.3 10.3 10.2 16.4 18.8 19.7 15.6 18.2 22.6 19.9 ...
..$ Girth : num [1:31] 8.3 8.6 8.8 10.5 10.7 10.8 11 11 11.1 11.2 ...
..- attr(*, "terms")=Classes 'terms', 'formula' length 3 Volume ~ Girth
.. .. ..- attr(*, "variables")= language list(Volume, Girth)
.. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
.. .. .. ..- attr(*, "dimnames")=List of 2
.. .. .. .. ..$ : chr [1:2] "Volume" "Girth"
.. .. .. .. ..$ : chr "Girth"
.. .. ..- attr(*, "term.labels")= chr "Girth"
.. .. ..- attr(*, "order")= int 1
.. .. ..- attr(*, "intercept")= int 1
.. .. ..- attr(*, "response")= int 1
.. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
.. .. ..- attr(*, "predvars")= language list(Volume, Girth)
.. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
.. .. .. ..- attr(*, "names")= chr [1:2] "Volume" "Girth"
..$ Volume: num [1:31] 10.3 10.3 10.2 16.4 18.8 19.7 15.6 18.2 22.6 19.9 ...
..$ Girth : num [1:31] 8.3 8.6 8.8 10.5 10.7 10.8 11 11 11.1 11.2 ...
..- attr(*, "terms")=Classes 'terms', 'formula' length 3 Volume ~ Girth
.. .. ..- attr(*, "variables")= language list(Volume, Girth)
.. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
.. .. .. ..- attr(*, "dimnames")=List of 2
.. .. .. .. ..$ : chr [1:2] "Volume" "Girth"
.. .. .. .. ..$ : chr "Girth"
.. .. ..- attr(*, "term.labels")= chr "Girth"
.. .. ..- attr(*, "order")= int 1
.. .. ..- attr(*, "intercept")= int 1
.. .. ..- attr(*, "response")= int 1
.. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
.. .. ..- attr(*, "predvars")= language list(Volume, Girth)
.. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
.. .. .. ..- attr(*, "names")= chr [1:2] "Volume" "Girth"
- attr(*, "class")= chr "lm"
list裡的每一項目,有可能是單一元素,array,data.frame或是再一層list。這個list和Lesson 2我隨便編的list長得不太一樣,是因為它每一項目都取了名字。
在str()裡看到接在$後面的就是名稱。list和data.frame都有這種用 "$名稱" 提取項目或變數的功能。而且list可能有好幾個階層,如果階層太深太大,可以再用str(fit[[]])去看細項的內容。用這種方式往下拆解,不管你想取的東西藏在物件哪一層哪一個位置,一定能抓出來。
> names(fit)
> str(fit[[7]])
> str(fit[[7]][[1]])
> str(fit$model); str(fit[[12]])
> str(fit[[7]][[1]])
> str(fit$model); str(fit[[12]])
> fit$model$Girth
再來注意到str()裡的一堆attr()。attr是屬性,這個東西就像是給你的物件貼個標示加註解一樣,一般自己定義的屬性對資料本身不會產生什麼影響。那些內建的重要屬性被改了,東西才會比較不一樣。抓其中一個例子來看:
> str(fit[[7]][[1]])
num [1:31, 1:2] -5.57 0.18 0.18 0.18 0.18 ...
- attr(*, "dimnames")=List of 2
..$ : chr [1:31] "1" "2" "3" "4" ...
..$ : chr [1:2] "(Intercept)" "Girth"
num [1:31, 1:2] -5.57 0.18 0.18 0.18 0.18 ...
- attr(*, "dimnames")=List of 2
..$ : chr [1:31] "1" "2" "3" "4" ...
..$ : chr [1:2] "(Intercept)" "Girth"
- attr(*, "assign")= int [1:2] 0 1
這是典型的二維array,矩陣的結構。在R裡array, matrix很類似,arrya主要出現在三維以上。
這是一堆數字 num 排成的31*2的矩陣 [1:31, 1:2] ,然後列了一些前面的數據最代表。
屬性附上了行列名稱(dimnames)用一個list加註在這個矩陣上。
在?attr列出的特殊屬性代表有:class, comment, dim, dimnames, names, row.names, tsp,其他的屬性都是作者自己加註解上去的,像是這裡的"assign”這項。
另外這裡先對R的函數有個小認識:一般函數是不能被 <- 指到、被改存的,只有極少數的函數有此功能,都是極重要的函數。
> head(X, 1); X[1, ]
> head(X, 1) <- 1 #ERROR
> X[1, ] <- 1
試這三行程式,同樣在看第一列資料:都是取出第一筆資料,但是如果要改寫,head是錯的,只能用[ ]取出要的資料來改寫。
而在?attr列出的一些特殊屬性,他們有對應的函數,可以調閱,可以改寫。像是attr(X, "dimnames")對應有dimnames(X)可以被改寫。
其實滿合理的:)
接著試著調閱或和更改屬性看看會發生什麼事吧!
> names(fit)
> X <- fit[[7]][[1]]
> str(X)
> attr(X, "dim")
> attr(X, "dimnames")
> dimnames(X)
> str(X)
> attr(X, "dim")
> attr(X, "dimnames")
> dimnames(X)
> attr(X, "assign")
> attr(X, "assign”) <- 1:5
> attr(X, "dim") <- c(2, 31); dim(X) <- c(2, 31)
> X
> X
> attr(X, "dimnames") <- list(1:2, 1:31); dimnames(X) <- list(1:2, 1:31)
> dimnames(X) <- NULL
> X
有點覺得這一篇寫到最後好像不是初學者的XD,不過先了解以後,看別人怎麼用,慢慢就會發現好處了

小結:
在知道怎麼使用[ ]、str()、attr家族後,面對任何亂七八糟物件裡取特定東西的這個問題上,已經沒有任何須要注意的了,而且應該也不會再遇到什麼問題。接著的問題應該是:要如何取出「符合XXX條件」的資料,有與趣可以先 ?which ?Logic。Lesson 4 要先講管了R世界另外更大半江山的help(),重點講如何自學R和資料分析。
文章標籤
全站熱搜