2016年11月27日 星期日

R_2016_TMU_第二次上課

#################################################
# 第一章
# 資料的輸入與輸出
#################################################
## http://biostat.tmu.edu.tw/R/20161125/#2  ##
setwd("D:/R_work/")  # 設定工作目錄 # 斜線是由右到左!!
#用ls()來看
## 文字檔輸入 ##
babies = read.table("babies.txt", header=T)  ## =是指派,大寫T是邏輯值!
babies = na.exclude(babies)  # 刪除具有遺失值的資料
Iris = read.table("iris_dataset.txt", header=F, sep=",")
IRIS = read.csv("iris.csv", header=F)#.csv的格式也依樣是用逗號分隔
babies1 = read.fwf("babies.txt", header=T)  ## =是指派,大寫T是邏輯值!
## 文字檔輸出 ##
cat(babies$smoke, file="smoke1.txt", sep="")
write(babies$smoke, file="smoke2.txt", sep=",") # ncolumns 5, 每五個換行!
weight = babies[babies$weight < 100,]
height = babies[babies$height > 70,]
write.table(weight, file="weight.txt", sep=",", row.names=F)
write.csv(height, file="height.csv", row.names=F)

## 存取其他軟體的資料檔 ##
library(gdata)
babies_xls = read.xls("babies.xls", sheet=1)  # 讀取xls檔, 需要perl的路徑!
library(xlsx) #用R 32較方便,用64也其他問題!
babies_xlsx = read.xlsx("babies.xlsx", sheetIndex=2)  # 讀取xlsx檔,且指定work sheet number!
write.xlsx(iris, "iris.xlsx", sheetName="iris")  # 匯出xlsx檔, 可以發現速率很慢!
library(sas7bdat)
babies_sas = read.sas7bdat("babies.sas7bdat")  # 讀取sas資料檔
library(foreign)
babies_spss = read.spss("babies.sav", to.data.frame=T)  # 讀取spss資料檔

## 存取R物件 ##
save(weight, height, file="babies.RData")#要存幾個資料都可以 用逗號分隔!
save.image()  # 儲存工作空間
load("babies.RData")  #可以用 ls()來確定 已經把資料存入!


#################################################
# 第二章
# 程式流程控制
#################################################

## 邏輯判斷式 ##
## 運算子優先性:
##  括弧 => 乘除 => 加減 => 比較 => 邏輯 => 指派
x = 1
x == 3
x != 1 + 2
!(x <= 3)
x %in% 1:5  #X有在 1-5裡面嗎?!!
x < 0 || x > 5  # || 表示 or  !
(is.matrix(x) || x >= 0) & (1 < 2)

## 條件執行 ##
x = 1
if (x == 3) y = 10 else y = 20
if (x >= 5) {         #()小瓜號, {}大括號!
y = 15
} else {
y=0
}  # 建議寫法
if (x < 0) {
y = x - 1
} else if (x > 0) {    #else if, 如果不是,我在判斷x, 如果是的話...!
y = x + 1
} else {
y = x
}

## for迴圈 ##       適合我已經知道要跑幾次!!!
y = vector()  # 宣告變數, 因為Y有用到 指標 []!
for (x in 1:5) { #for 迴圈就是先要說明x的範圍!!!
y[x] = sqrt(x)
}
z = 1  #起始值!
for (i in c(2,4,6,8,10)) {
z = z * i
}  # 2*4*6*8*10

## while迴圈 ##      還不清楚要跑幾次!
x = 1; y = vector()
while (x <= 5) { #while 迴圈就是先有一個判斷式!
y[x] = sqrt(x)
x = x + 1
}
z = 1; i = 2
while (i <= 10) {
z = z * i
i = i + 2
}

## repeat迴圈 ##
x = 1; y = vector()
repeat {
y[x] = sqrt(x)
x = x + 1
if (x > 5) break  # 跳離迴圈
}
z = 1; i = 1
repeat {
i = i + 1
if (i > 10) {break} else if (i %% 2 != 0) {next} ## "%%" i 除以 2的餘數 不等於0!!
z = z * i
}  # next: 跳過一次迴圈


#################################################
# 第三章
# 自訂函數
#################################################

## R的自訂函數 ##
# 函數的定義語法:
# 自訂function名稱 = function(參數1, 參數2, ...)
# {
# 完整運算式...
# }

func1 = function(a, b)
{
x = 1+2*3/4        ##這個x只有存在此函數內, 部會影響到外面的x!!
y <<- a + b        ## <<- 指派 把這個y指派到外部的變數了!!!
return(y)  # 預設傳回最後一個運算值,或使用return函數
}
func1(7, 6)
func1(b=3, a=2)

## 參數的預設值 ##
func2 = function(x=0)
{
sum(x)/length(x)
}
func2(1:5)
func2()  # 參數x的預設值為0

## ...參數 ##
func3 = function(x, ...)    ## ... 就把此部分的參數 轉移到函數內
{
y = mean(x, ...) + 1
return(y)
}
x = c(2,4,6,NA,10)
func3(x, trim=0.1)
func3(x, trim=0, na.rm=TRUE)

## 二元運算子 ##
"%p%" = function(a, b)    ## 一定要有雙引號百分比!!
{
factorial(a)/factorial(a-b)
}
5 %p% 2


#################################################
# 第四章
# 程式撰寫技巧
#################################################

## apply函數 ##
apply(iris[-5], 2, max)
func = function(x) x[x < mean(x)]
apply(iris[,1:4], 2, func)

## tapply函數 ##
tapply(iris[,1], iris[,5], min)
index2 = rep(1:2, length=150)
tapply(iris[,2], list(iris[,5],index2), median)

## sapply, lapply函數 ##
sapply(iris, length)   #對每個元素, 優先回傳vector!
lapply(iris, length)   #對每個元素, 回傳list!
sapply(iris[-5], function(x) { which(x > mean(x)) })

## 各方法計算時間比較 ##
x = rnorm(50000)  # 以標準常態分配生成隨機樣本
y1 = y2 = y3 = y4 = vector()
t0 = proc.time()  # 起始時間
for (i in 1:length(x)) {
if (x[i] <= 0) y1[i] = -1 else y1[i] = 1
}
t1 = proc.time() - t0                 # y1的計算時間
y2 = ifelse(x <= 0, -1, 1)
t2 = proc.time() - t0 - t1            # y2的計算時間
y3[x <= 0] = -1; y3[x > 0] = 1
t3 = proc.time() - t0 - t1 - t2       # y3的計算時間
y4 = sapply(x, function(x) {if (x <= 0) -1 else 1})
t4 = proc.time() - t0 - t1 - t2 - t3  # y4的計算時間

## Which is better? ##    #寫程式比的是 執行效率 and 開發成本(可讀性, 註解, 排版, debug)!
aa=read.table("babies.txt",header=TRUE)
bb=na.exclude(aa$smoke);cc=vector()
for(i in 1:length(bb)){if(bb[i]==1) cc[i]="是" else cc[i]="否"}

## 讀入babies資料檔、宣告smoke及new_var變數 ##
babies = read.table("babies.txt", header=TRUE)
smoke = na.exclude(babies$smoke)
new_var = vector()

## 使用迴圈將smoke變數重新編碼並存入new_var變數 ##
for (i in 1:length(smoke)) {
if (smoke[i] == 1) {
new_var[i] = "是"
} else {
new_var[i] = "否"
}
}
================================================


########################################################
##          R 軟體系列課程 - R 軟體入門(二)
##          課堂練習題參考答案
##          2016/11/25
########################################################


########################
##  資料的輸入與輸出  ##
########################

## 讀入外部資料檔"babies.txt"
babies = read.table("babies.txt", header=TRUE)  # 參數視資料檔內容而定

## 分別將 babies 及 iris 匯出成 csv 檔且不包含列名稱
write.csv(babies, file="babies_csv.csv", row.names=FALSE)
write.csv(iris, file="iris_csv.csv", row.names=FALSE)

## 將 babies 及 iris 儲存至同一個 RData 檔
save(babies, iris, file="datasets.RData")


####################
##  程式流程控制  ##
####################

## 利用迴圈輸出一個九九乘法表
for (i in 1:9) {
for (j in 1:9) {
cat(j, "*", i, "=", i*j, sep="")
cat("\t")  # Tab對齊
}
cat("\n")  # 換行
}  # 可嘗試以 while 或 repeat 迴圈改寫

## 利用matrix()函數的性質, 2016/11/27 自寫!
func=function(a)
{y=matrix(,a,a)
for (i in 1:a) {
for(j in 1:a){
y[j,i]=i*j
}
}
y
}


## (亂數)產生一個1~100的整數,進行猜數字遊戲。
## 根據輸入的猜測數字提示大於或小於正確答案!
## Hint:無窮迴圈、scan()
ans = sample(10, 1)  # 從1~100中隨機抽出一個值
repeat {
cat("請輸入一個介於1~100的整數:\n")
guess = scan(n=1, quiet=TRUE)  # 提供使用者輸入介面
if (guess == ans) {
cat("答對囉!答案就是", ans, "!\n", sep="")
break  # 重要!否則就猜不完囉~
} else {
tip = ifelse(ans > guess, "大", "小")
cat("正確答案比", guess, "還要", tip, "喔!再試一次吧!\n", sep="")
}
}


################
##  自訂函數  ##
################

## 定義一個參數為三角形三邊長的函數,回傳值為三角形種類(正三角形、等腰三角形……)
triangle = function(x)
{
sx = sort(x)
if (length(sx) != 3 || (sx[1] + sx[2]) <= sx[3]) {
return("不是三角形")
} else if (sx[1] == sx[3]) {
return("正三角形")
} else if (sx[1] == sx[2] || sx[2] == sx[3]) {
return("等腰三角形")
} else {
return("其他三角形")
}
}  # 嘗試加入判斷直角三角形

## 定義一個可計算階層數的函數
## Hint:利用遞迴呼叫,0! = 1
f = function(x)
{
if (x <= 1) {
return(1)
} else {
return(x * f(x - 1))
}
}

## 定義一個可進行組合數計算的二元運算子
## 註:n 取 r 的組和數 = n! / r! / (n-r)!
"%c%" = function(n, r)
{
f(n) / f(r) / f(n - r)
}


####################
##  程式撰寫技巧  ##
####################

## 計算 babies 資料集中每一個變數的遺失值個數
func = function(x)
{
sum(is.na(x))  # 對邏輯值進行運算時,TRUE = 1;FALSE = 0
}
apply(babies, MARGIN=2, FUN=func)

## 以 smoke 為分組變數,繪製 parity 變數的次數表
tapply(babies$parity, INDEX=babies$smoke, FUN=table)

沒有留言: