程式設計第一堂課的心得─關於R還有一些重要概念


這是統計系系上開的必修課,跟資工系的程式設計並不一樣,目前是學習使用軟體R來處理統計上的問題。今天講完R基本指令、定義方式,試著寫算術平均數、變異數、標準差、absolute deviation(這個中文不曉得怎麼翻譯)function(一套解決問題的作用程序,我的疑問是程式上講的function似乎和數學上的function不太一樣,最後再多談一些)
基本指令、定義方式
對一個代號x定義值,可藉由輸入
x=4

x<-4
想要顯示x的結果,就輸入x然後按enter就行了
x
[1]  4前面那個[1]是數數的,只是現在東西不夠多,如果夠多的話到下一列,下一列的開頭也許就會顯示[11][26]之類的,意思是這一列從第11個或第26個開始,依此類推
對一個代號x定義為行向量,可藉由輸入
x=c(4,5,6)

x<-c(4,5,6)
注意,這時候x到底是什麼呢?x已經變為一個向量,對x作為向量的定義已經覆蓋了之前整數的定義,所以x=(4,5,6)一個代號不能有兩個意義
x
[1]  4  5  6

x[1]
是對程式要求顯示向量第一個component或代表向量第一個component的意思,例如現在x=(4,5,6)
x[1]
[1]  4
想要對程式要求顯示多個component,例如第一個和第二個,可藉由打
x[c(1,2)]
就會顯示
[1]  4  5想要哪些欄位就仿照這個形式輸入數字,就會顯示第幾欄位的component
特殊的:a<-c(1:10),是定義a為一個10components的行向量,且component正是從1排到10,不過如果是較一般的向量,component較不規則的,還是要自己一個一個輸入數字。
a
[1]  1  2  3  4  5  6  7  8  9  10
關於四則運算和次方,用的符號是+-*/^,這就不多講了,就像一般算式一樣輸入進去,R讀的懂

ls()
:這是R內建的function,我覺得它非常重要,在有時候可能也會非常好用,它的功能是看working space裡的東西,就是你已經定義了什麼,像剛剛已經對xa定義了,如果我使用它
ls()
[1]  “x”  “a”
代表說我現在有兩個東西─xa可用,就好像是找工具箱裡有哪些現成工具,如果沒有你要的工具,在情況許可下,你可以自己創造,這也是資訊工程師和其他類的工程師很不一樣的地方
另外一個系統內建functionlength()()內輸入向量,它會算出這個向量有幾個component,例如:
n=length(x)
n
[1]  3
x=(4,5,6)
它有3component,因此n=3這跟數學上向量長度的定義不太一樣,數學上是把每個component平方,取和,再開跟號
基本的指令和定義方式學會了,現在要做平均數、變異數、標準差的function觀察公式、從所求想起,裡頭有一個共同牽涉到的運算─summation,而這也是之前的簡單指令所很難表達的,一個一個加起來?該如何用程式做出summation這個動作?有一個解法是for迴圈,for迴圈可「重複執行同一性質的某動作」,平均數就是把一群數加起來再除以它們的總數,過程就是一直+for迴圈的特性正好符合我們的需求,不過且慢,在談技術細節之前,我要談一件更重要的事情,看起來也許平淡無奇,其中牽涉到思考基本規則。
我們小學學過一個四則運算基本觀念,若是碰到括號,括號內的運算要先做,例如(4+5)x3,雖然xpriority(優先權)+高,但()更高,所以是先做(4+5)=9,再9x3=27運算有priority高低之分+-x/()priority若是沒有差別,一律從最前面做到尾,()此時沒有任何意義,一些基本規則也不再成立,例如2x(3+5)=6+5=11(原有的分配律不成立),以前(2+3+4+5)x(6+7+8+9)這種算式在處理上完全沒問題,但在「一律從最前面做到尾」的規則下,怎表?一個算式表不出來,得寫兩個算式,先2+3+4+5=14,再6+7+8+9x14,這只是簡單的先做兩堆的和再相乘而已,如果乘更多項或除更多項,得寫幾個算式才能解決啊?捨棄priority()最高、x/次之、+-最低的模式,光是表達算式上的弊病就讓人對其敬而遠之了,這麼定的唯一效用可能是讓小孩子一開始學初等算術覺得簡單些了,但過不久他們可能會開始厭惡數學課,因為總是要寫好多算式,搞的糊里糊塗的了。(一時只想到表達形式上的問題,可能還有其他問題是我沒想到的)





上一段是我一時有感而發寫的,有點扯遠,但別忘記這個重點:運算有priority高低之分,整篇文章其他東西都忘記或不看無所謂,只要記得這句話就夠了,它潛在的重要性可能超乎你的認知;一開始講那些R的基本指令其實也只是幫自己複習而已,對沒在學的人根本不重要;上面那個公式很明顯是取和,其中的運算很簡單:就是第一個+第二個+第三個+…+n個。問題在於剛才講到的基本指令無法表達或很難表達,現在想借助for迴圈來幫我們解決。

sum<-function(x){ n<-length(x)

        temp<-0
        for( i in 1:n)temp<-temp+x[i]
                             return(temp)
                           }
假定這時候x=(1,2,3,…,n)
第一行的意思是定義一個function叫做sum{ }裡是function的內容,n<-length(x)就是把n定為向量xcomponent數目;第二行和第三行特別一些,定義temp0(或者說賦值temp0,賦值是個好字,很白話,就是給它一個值,在跟一個同學聊天時講到的)for( i in 1:n)意思是後面的程序是從i=1開始做,再來i=2, i=3…, i=n,看到那個<-,應該也猜到式子的priority了吧,沒錯,就是先把temp+x[1],再把這個值給temp,覆蓋原本為0的定義,還記得「一個代號不能有兩個意義」吧,經過一輪後temp=0+1=1了,第二輪temp=1+2=3…,加到n的時候,temp就會是1,2,3,…累加到n了,獲得了總和,但程式有inputoutput,兩個都非常重要,必須規範清楚,現在要function輸出什麼?總和,那就是temp了,return(temp)是把temp丟出去的意思,這樣結果才會呈現,不然會沒有任何東西,終於達到目的了。
其他的是比較零碎的心得和筆記,短短的句子,就直接條列在下面了,這對其他人可能較無價值
1.
必須清楚規範inputoutput
2.程式裡運用的物件都必須定義清楚
3.
思考:想要什麼作用、作用的order、已定義的代號、未定義的代號
4.
一個代號只能有一個意義,不能同時有兩個意義,這點像數學上function定義域裡的元素
5.
當我先前已經定義好某function f,我在g裡可直接引用f來作用
6.function
內部設的東西不會出現在working space或者覆寫原有的代號意義,舉例來說,在外部我已定義n=10,在function內部我又使用了n這個代號,我在function內定n=8,並不再改變它,在function的作用期間遇到n皆為8,但後來查working space裡的n還是10,所以function內部對代號的設定似乎不會改變working space的設定;但在function有用到n,卻沒在function內定義n,那function會拿working space裡的n來用,也就是視n10
沒時間講function了,而且根據經驗,如果拖過隔天,這篇文章很可能就發不出去了,function在程式上和在數學上的意義似乎不太一樣,改在別篇文章再談,應該不會太長。

留言

  1. 跟我現在的機電程式課一樣,要寫MATLAB,我們似乎都要學跟自己相關的計算程式,MATLAB可以算矩陣反矩陣10x10的矩陣不用1秒就跑出來了。

    回覆刪除
    回覆
    1. 另外一件事,coding style很重要,一些小細節的習慣可能在寫小程式看不出有什麼好壞,但在大型一點的程式就會看出來了

      http://blog.vgod.tw/2008/07/05/%e8%bf%bd%e6%b1%82%e7%a5%9e%e4%b9%8e%e5%85%b6%e6%8a%80%e7%9a%84%e7%a8%8b%e5%bc%8f%e8%a8%ad%e8%a8%88%e4%b9%8b%e9%81%93%e4%b8%80%ef%bc%89/

      我中間段落打的「運算有priority高低之分」,是打文章中途一時想到的,以前我也沒想過,可能真的很重要啊...

      刪除

張貼留言

這個網誌中的熱門文章

為什麼我覺得一些商管或財經雜誌的內容沒有價值

為什麼(-1)x(-1)=+1、不定義分母為0的分數

科學和宗教似乎有本質上的衝突、一些讓我敬謝不敏的玄論