2018年4月7日 星期六

R資料匯入與匯出

R資料匯入與匯出

# read.table
# read.csv
# read.fwf
檔首無BOM
# readxl 套件
RODBC 套件
# lapply
# do.call

本篇說明資料匯入與匯出。首先介紹ETL概念,其次介紹常用的資料檔案,包括文字檔案、Excel檔案、資料庫資料、JSON檔案。資料庫的匯入將以Microsoft SQL Server說明為主。最後以單一檔案較大者的「大型資料」匯入與檔案數目較多者的「大量資料」匯入等議題做為本篇的結束。

1. ETL簡介


隨著科技的進步,企業經常面對資料處理、轉換或整合等應用。「ETL (Extract-Transform-Load)擷取轉換載入」是資料分析中的基礎的應用,最早興起於1970年資料倉儲中資料庫的處理程序。ETL表示資料由資料來源端擷取 (Extract) 出來,經過轉換 (Transform),再載入 (Load)到目的端的資料傳輸整體過程。進行ETL程序時,常用串流方式方法避免資料讀取時記憶體耗盡,參考圖1所示。


圖1 ETL流程圖

擷取:從各種不同的資料來源中,將資料擷取出來。資料來源包括交易型資料庫,同質資料與異質資料來源,資料擷取具有以下特性:

  1. 可能有各式各樣的資料來源和不同的資料格式,在利用程式語言開發或使用現有工具時,必須將來源資料轉換成共同資料格式。
  2. 擷取出來的資料,比對其格式和結構是否符合所需,例如:是固定欄位長度內容的資料、還是用區隔符號定義的資料。
  3. 擷取出來的資料若不符合所需,則依照相對應的規則以決定該採取何種反應,如:另外紀錄錯誤問題並發出警告,但整個ETL流程仍繼續執行。
  4. ETL作業能擷取一個檔案或同時進行多個來源端的資料擷取。

轉換:對資料進行適當的轉換,如型態轉換、字串相連、彙總運算等,本階段會將資料儲存成適當的格式,以利事後查詢與分析。這個步驟在 ETL 中不一定需要執行。

資料轉換具有以下特性:

  1. 可針對Excel、HTTP Web Page、XML、PDF與 Binary data 資料格式等檔案格式進行資料轉換。
  2. 基於商業邏輯上的需求,必須依照應用程式資料的特性來分類、匯總、轉換資料型態;或是把經年累月所聚集的歷史資料來作合併、統計、分折及計算。
  3. 本階段的轉換元件與功能通常是最多元、最豐富的,往往也是決定ETL產品的重要考量之一。
  4. 資料轉換就是將所擷取出之資料,交付予資料轉換元件(例:log資料轉換元件),逐一並循序地依照所設計好的規則進行轉換。
  5. 載入:將資料載入目的端,目的端通常是為了報表產製及商業智慧分析而最佳化的資料倉儲。

2. 文字檔案

常用的文字檔案包括以逗號分隔值檔案(Comma-Separated Values File,簡稱CSV File),其檔案以純文字形式儲存數字和文字資料。CSV檔案亦稱為字元分隔值檔案(Character-Separated Values File),因為分隔字元也可以不是逗號,例:分號(;)、Tab符號(–>)、bar符號(|)與空白字元。CSV檔案具有以下特性:


  1. 採用純文字,使用某個字元集,例:ASCII、Unicode、UTF-8或GB2312(簡體中文環境)等儲存。
  2. 每一橫列為一筆記錄組成。
  3. 每一筆記錄以分隔符號區分欄位。
  4. 每一筆記錄都具有相同的欄位順序。
  5. 在Windows環境中使用 Microsft Office Excel 等軟體執行 檔案\另存新檔\存檔類型\ 選取「CSV(逗號分隔)()*.csv」 \ 按儲存 即可儲存為CSV檔案。
  6. 開啟CSV檔案時,最後一列為空白列,該空白列須保留不可刪除,否則匯入至R/Python會有問題。參考圖2,其中第12列為空白列。


圖2 production.csv範例

範例1:匯入production.csv檔案。

CSV檔案匯入與資料分析工作包括以下五大步驟:


步驟1 設定工作目錄:

一般資料的匯入與匯出可以先考量工作目錄的概念。R/Python軟體具有工作目錄(Working Directory)概念,即預設讀取資料的目錄。以下說明以Windows 10作業系統與R軟體[https://www.r-project.org/]操作為主。使用getwd函數以取得工作目錄,設定工作目錄為setwd函數。本範例考慮工作目錄為「C:/rdata」。

setwd("C:/rdata")
getwd()
## [1] "C:/rdata"

步驟2 準備資料檔案:


本步驟為準備好即將匯入至R的資料檔案,一般初步使用建議將資料轉換為CSV檔案較方便於後續資料匯入。下載production.csv並儲存至C:\rdata,資料來源:http://web.ydu.edu.tw/~alan9956/rdata/production.csv

步驟3 匯入資料:

常用匯入資料為read.table函數,使用彈性較大,read.csv函數為限用CSV檔案。本例使用read.table函數以匯入CSV檔案。“production.csv”表示檔案名稱,header=TRUE表示第一列為資料欄名稱,sep=“,”表示資料以逗號區隔欄位,stringsAsFactors=FALSE表示不會將字串自動轉換為因子(Factor),而保持原字串資料型態。匯入至R之資料物件名稱為production,資料顯示為10筆,5個欄位。如果匯入資料產生亂碼情形,則可考慮以下三種解決方式:

  1. 使用記事本等軟體,將資料另存新檔且編碼設定為ANSI。
  2. 在read.table函數中加入 fileEncoding=“UTF-8”或適當編碼。
  3. 在read.table函數中加入 encoding=“UTF-8”或適當編碼。


production <- read.table("production.csv", header=TRUE, sep=",", stringsAsFactors=FALSE)
production
##    工號 生產日期 機台 生產量 目標量
## 1     1 2017/4/1    A     50     60
## 2     2 2017/4/1    A     60     60
## 3     2 2017/4/1    A     40     60
## 4     2 2017/4/2    B     70    100
## 5     3 2017/4/2    B    120    100
## 6     3 2017/4/3    B     80    100
## 7     4 2017/4/3    C     30     50
## 8     1 2017/4/4    C     35     50
## 9     4 2017/4/4    C     60     50
## 10    2 2017/4/4    C     80     50

步驟4 資料分析:

資料匯入完成後,首要步驟是分別使用str函數與summary函數進行資料結構理解與統計摘要分析。int表示整數(Integer),chr表示字串(String)或稱為字元(Chacter)。summary函數會輸出以下6個統計量:

  1. Min :最小值(Minimum)
  2. 1st Qu :25百分位數,符號 Q1
  3. Median :中位數,符號 Q2
  4. Mean :平均數
  5. 3rd Qu :75百分數位,符號 Q3
  6. Max :最大值(Maximum)

str(production)
## 'data.frame':    10 obs. of  5 variables:
##  $ 工號    : int  1 2 2 2 3 3 4 1 4 2
##  $ 生產日期: chr  "2017/4/1" "2017/4/1" "2017/4/1" "2017/4/2" ...
##  $ 機台    : chr  "A" "A" "A" "B" ...
##  $ 生產量  : int  50 60 40 70 120 80 30 35 60 80
##  $ 目標量  : int  60 60 60 100 100 100 50 50 50 50
summary(production)
##       工號       生產日期             機台               生產量     
##  Min.   :1.0   Length:10          Length:10          Min.   : 30.0  
##  1st Qu.:2.0   Class :character   Class :character   1st Qu.: 42.5  
##  Median :2.0   Mode  :character   Mode  :character   Median : 60.0  
##  Mean   :2.4                                         Mean   : 62.5  
##  3rd Qu.:3.0                                         3rd Qu.: 77.5  
##  Max.   :4.0                                         Max.   :120.0  
##      目標量   
##  Min.   : 50  
##  1st Qu.: 50  
##  Median : 60  
##  Mean   : 68  
##  3rd Qu.: 90  
##  Max.   :100
# 新增達成率欄位,計算方式為生產量/目標量
production$達成率 <- round((production$生產量/production$目標量)*100)
production
##    工號 生產日期 機台 生產量 目標量 達成率
## 1     1 2017/4/1    A     50     60     83
## 2     2 2017/4/1    A     60     60    100
## 3     2 2017/4/1    A     40     60     67
## 4     2 2017/4/2    B     70    100     70
## 5     3 2017/4/2    B    120    100    120
## 6     3 2017/4/3    B     80    100     80
## 7     4 2017/4/3    C     30     50     60
## 8     1 2017/4/4    C     35     50     70
## 9     4 2017/4/4    C     60     50    120
## 10    2 2017/4/4    C     80     50    160

# 繪製達成率統計圖
plot(production$達成率, xlab="人次", ylab="達成率(%)", main="2018年達成率統計圖", type="b", sub="製表:RWEPA, March 12, 2018")


步驟5 匯出分析結果:

最後步驟是將分析的結果,包括文字與圖檔等進行資料匯出,常用的文字資料匯出函數是write.table與R專用資料格式(RData)save函數。本例使用write.table函數 匯出成production.output.csv檔案,使用save函數匯出成production.output.RData。

write.table(production, file="production.output.csv", sep=",", row.names=TRUE)
save(production, file="production.output.RData")

如果文字檔案是採用固定寬定方式儲存,則匯入資料時可採用  read.fwf 函數匯入。例:固定寬度檔案名稱是 myfix.txt,資料寬度分別為1, 2, 3個空白字元, 4個字元,則匯入方法如下,其中 -3 表示跳過3行不讀取:

read.fwf("myfix.txt", widths = c(1, 2, -3, 4))

3. Excel檔案

Excel檔案是常用辦公室資料檔案格式,除了以Microsoft Office Excel軟體進行操作,另外可使用readxl套件匯入Excel檔案並進行資料操作處理。

範例2:匯入 production.xlsx 檔案。

首先將範例1的 production.csv 另儲存成 production.xlsx。使用 excel_sheets函數理解工作表個數,使用 read_excel讀取工作表,其中mydf1,mydf2,mydf3結果皆相同。

library(readxl)
# 顯示工作表名稱
datasets <- "production.xlsx"
excel_sheets(datasets)
## [1] "production"
# 讀取Excel檔案
mydf1 <- read_excel(datasets) # 預設讀取第1個工作表
mydf2 <- read_excel(datasets, 1) # 指定第1個工作表
mydf3 <- read_excel(datasets, "production") # 指定工作表名稱

mydf1
## # A tibble: 10 x 5
##     工號 生產日期            機台  生產量 目標量
##    <dbl> <dttm>              <chr>  <dbl>  <dbl>
##  1  1.00 2017-04-01 00:00:00 A       50.0   60.0
##  2  2.00 2017-04-01 00:00:00 A       60.0   60.0
##  3  2.00 2017-04-01 00:00:00 A       40.0   60.0
##  4  2.00 2017-04-02 00:00:00 B       70.0  100  
##  5  3.00 2017-04-02 00:00:00 B      120    100  
##  6  3.00 2017-04-03 00:00:00 B       80.0  100  
##  7  4.00 2017-04-03 00:00:00 C       30.0   50.0
##  8  1.00 2017-04-04 00:00:00 C       35.0   50.0
##  9  4.00 2017-04-04 00:00:00 C       60.0   50.0
## 10  2.00 2017-04-04 00:00:00 C       80.0   50.0

mydf2
## # A tibble: 10 x 5
##     工號 生產日期            機台  生產量 目標量
##    <dbl> <dttm>              <chr>  <dbl>  <dbl>
##  1  1.00 2017-04-01 00:00:00 A       50.0   60.0
##  2  2.00 2017-04-01 00:00:00 A       60.0   60.0
##  3  2.00 2017-04-01 00:00:00 A       40.0   60.0
##  4  2.00 2017-04-02 00:00:00 B       70.0  100  
##  5  3.00 2017-04-02 00:00:00 B      120    100  
##  6  3.00 2017-04-03 00:00:00 B       80.0  100  
##  7  4.00 2017-04-03 00:00:00 C       30.0   50.0
##  8  1.00 2017-04-04 00:00:00 C       35.0   50.0
##  9  4.00 2017-04-04 00:00:00 C       60.0   50.0
## 10  2.00 2017-04-04 00:00:00 C       80.0   50.0

mydf3
## # A tibble: 10 x 5
##     工號 生產日期            機台  生產量 目標量
##    <dbl> <dttm>              <chr>  <dbl>  <dbl>
##  1  1.00 2017-04-01 00:00:00 A       50.0   60.0
##  2  2.00 2017-04-01 00:00:00 A       60.0   60.0
##  3  2.00 2017-04-01 00:00:00 A       40.0   60.0
##  4  2.00 2017-04-02 00:00:00 B       70.0  100  
##  5  3.00 2017-04-02 00:00:00 B      120    100  
##  6  3.00 2017-04-03 00:00:00 B       80.0  100  
##  7  4.00 2017-04-03 00:00:00 C       30.0   50.0
##  8  1.00 2017-04-04 00:00:00 C       35.0   50.0
##  9  4.00 2017-04-04 00:00:00 C       60.0   50.0
## 10  2.00 2017-04-04 00:00:00 C       80.0   50.0

範例3:參考圖3,使用Excel開啟CSV檔案會有亂碼情形。

圖3 CSV檔案亂碼

改善方式之一是考慮使用文字編輯軟體,修改編碼方式,本例使用免費軟體Notepad++,將編碼由原先的「編譯成UTF-8碼(檔首無BOM)」修改為「編譯成 UTF-8 碼」,再儲存檔案後使用Excel開啟即沒有亂碼,詳細參考圖4之設定。

圖4 CSV檔案亂碼-UTF-8

4. 資料庫資料


關於微軟(Microsoft)大量結構性資料匯入與匯出,Microsoft SQL Server提供以下工具:

  1. bcp公用程式 (bulk copy program): 提供大量資料匯入與匯出功能,可以由使用者指定格式,在 Microsoft SQL Server 執行個體與資料檔案之間大量複製資料。
  2. BULK INSERT 陳述式:可將資料直接從資料檔案匯入至資料庫資料表或非資料分割的檢視,不提供匯出資料功能。
  3. BULK INSERT 陳述式與 INSERT…SELECT * FROM OPENROWSET(BULK…) 陳述式 :將大量資料檔案匯入到 SQL Server 資料表中,不提供匯出資料功能。
  4. SQL Server Data Tools (SSDT) 來執行 SQL Server 匯入和匯出精靈。

資料來源:https://docs.microsoft.com/zh-tw/sql/relational-databases/import-export/bulk-import-and-export-of-data-sql-server

R可採用 RODBC 套件與Microsoft SQL Server資料庫連結,其中 sqlQuery 函數可執行資料匯入至R/R物件寫入SQL資料庫,部分執行畫面參考圖5,詳細參考 RODBC 與 SQL Server 資料匯入與寫入

圖5 RODBC-寫入

5. JSON檔案


JSON(JavaScript Object Notation)是一種由Douglas Crockford 構想和設計、輕量級的資料交換語言,該語言以易於讓人閱讀的文字為基礎,用來傳輸由屬性值或者序列性的值組成的資料物件。儘管JSON是Javascript的一個子集,但JSON是獨立於語言的文字格式,並且採用了類似於C語言家族的一些習慣,詳細參考官方網站[http://www.json.org/]

資料來源:https://en.wikipedia.org/wiki/JSON

JSON資料物件包括:

  1. 物件 object : {name:value}
  2. 陣列 array : [x1, x2, …]

JSON資料型態包括:

  1. 空值(null)
  2. 邏輯值(true, false)暨布林值。
  3. 數值(number),沒有區分整數與具有小數點數。
  4. 字串(string)。

RJSONIO 套件提供以下二大函數,詳細參考函數線上說明:

  1. toJSON() : 轉換 R 物件為 JSON 字串。
  2. fromJSON() : 轉換 JSON物件為 R 物件, 資料來源包括 URL, File, R物件。


JSON資料參考圖1.4.6 JSON-錄影節目影片範例。

圖6 JSON-錄影節目影片範例

資料來源:http://vida.moc.gov.tw/VIDA411.ASP?ISSUEYM=10306

6. 大型資料


大型資料指的是單一檔案較大,使用傳統read.table或read.csv函數可能匯入時間教長,此時可使用data.table套件的fread函數以提升匯入效能,詳細參考以下圖7 大型資料範例。



圖7 大型資料範例

上述大型資料亦可使用 bigmemory套件匯入資料,參考圖8 大型資料-bigmemory範例。



圖8 大型資料-bigmemory範例

7. 大量資料


大量資料指的是檔案較多時,使用傳統 read.table或 read.csv函數逐一匯入較不方便,此時可使用 lapply函數,詳細參考以下大量資料範例,考慮將三個檔案,每個檔案是10列5行,合併為單一資料物件30列5行。

lapply 函數主要包括2個參數 lapply(資料物件, 函數),其回傳結果是串列(list):

  1. 第一個參數是須要處理的資料物件,一般是向量資料,本例 files 表示三個檔案路徑。
  2. 第二個參數是函數,本例是 read.table,後續 header=TRUE, sep="," 是配合 raed.table使用。

do.call 函數是將三個串列合併為一個資料框(data.frame)。

# 大量資料範例
working_path <- "C:/rdata"
setwd(working_path)
getwd()
## [1] "C:/rdata"
sample1 <- iris[sample(1:nrow(iris),10),]
sample2 <- iris[sample(1:nrow(iris),10),]
sample3 <- iris[sample(1:nrow(iris),10),]

write.table(sample1, file="sample1.csv", sep=",", row.names=FALSE)

write.table(sample2, file="sample2.csv", sep=",", row.names=FALSE)
write.table(sample3, file="sample3.csv", sep=",", row.names=FALSE)

files <- dir(getwd(), pattern="sample.*.csv", recursive=TRUE, full.names=TRUE)

files
## [1] "C:/rdata/sample1.csv" "C:/rdata/sample2.csv" "C:/rdata/sample3.csv"

tables <- lapply(files, read.table, header=TRUE, sep=",") # list

sample.all <- do.call(rbind, tables) # data.frame

str(sample.all)
## 'data.frame':    30 obs. of  5 variables:
##  $ Sepal.Length: num  5.4 4.7 5.7 6.3 6.6 7 5 4.4 5.4 6.3 ...
##  $ Sepal.Width : num  3.9 3.2 2.8 2.5 3 3.2 3.6 3 3 2.5 ...
##  $ Petal.Length: num  1.7 1.3 4.1 5 4.4 4.7 1.4 1.3 4.5 4.9 ...
##  $ Petal.Width : num  0.4 0.2 1.3 1.9 1.4 1.4 0.2 0.2 1.5 1.5 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 2 3 2 2 1 1 2 2 ...
# end

2018年2月16日 星期五

R與2018年狗年行大運 ^_^

在上一篇文章 [R與2017年金雞報喜^_^] 提及使用 cowsay 套件可繪製金雞報喜, 目前套件包括37種動物, 今年2018年沒有內建狗的資料, 因此本篇文章採建立新資料方式, 並繪製狗年行大運圖形, 參考以下範例:

關鍵字:

  • cowsay 套件
  • 2018年
  • dog

R程式:

# title: cowsay-狗年行大運
library(cowsay)
animals[38] <- 
'
<<              /-----\\\n
<<____________/ ( )    \\-o\n
|                   __/\n
<    狗年行大運 ^_^ / \n
(  ^_   ------\  << \n
< <  < \\       \\ \\ >> \n
\\_|  \\_|      /_/ //'

cat(animals[38])

繪圖結果:



# end

2017年11月2日 星期四

2017 R TAIWAN 研討會



會議名稱:2017 R TAIWAN 研討會

會議主軸:資料融合、分析與應用 (不限定R語言)
會議地址:台北市中正區貴陽街一段56號 (東吳大學城中校區)
會議教室:東吳大學城中校區 5211演講廳、5117教室、2123教室

宗旨:
Big Data 是近年來熱門的話題之一,根據 2016年 KDnuggets 的調查顯示,R仍然高居資料解析、資料探勘與資料科學主要程式語言的首位。但R絕對不是萬能無缺的!搭配其它資料處理與分析的工具,方能捕捉到 Big一字的意涵 – 從關鍵的數據中解析真正不同且重要的洞見。依稀記得補習班常用的一句廣告詞:好的老師帶你上天堂,平庸的老師讓你原地踏步。R 無疑是個關鍵且能造血活血的工具,包羅萬象的R套件可以持續提升我們的資料解析能力。除非妳(你)想安逸,否則會被它一步一步地往前推。人人都希望經常遇見好的老師,但好老師背後成功的原因是授之以漁,而非授之以魚。能活血造血的開源工具無疑可以成為我們的導師,所以強調跨域資料分析的資料科學家們一定要先慎選工具,再去投注寶貴的時間和金錢在艱辛的學習過程中。今年 2017 R Taiwan 研討會從雲端、產業根基與解析技術等開始談起,結合實務經驗豐富的業界專家與尖端研究的學界教授進行分享討論,期使 R軟體發揮槓桿作用,讓各行各業能從彈性的開源工具中取得資料加值的競爭優勢。

會議時間:2017/12/14 星期四 (研討會前導課程)2017/12/15 星期五 (研討會主議程)

會議網址:http://rtaiwan2017.fmhuang.net/
早鳥票報名網址: https://goo.gl/forms/IYUtY76EgRShd2Os1

研討會主議程報名費用:一般票1000元、早鳥票800元
研討會前導課程報名費用:一般票1500元、早鳥票1200元
線上報名時間:
早鳥票:2017/11/01 中午 12 點開始至 2017/11/13 中午 12 點止
一般票:2017/11/14 中午 12 點開始至 2017/12/04 中午 12 點止

主辦單位:東吳大學巨量資料管理學院、中華R軟體學會、臺灣資料科學與商業應用協會、國立臺北商業大學
合辦單位:國立臺北商業大學資訊與決策科學研究所
協辦單位:中華R軟體學會、臺灣資料科學與商業應用協會、臺北市商用數學發展協會、國立臺北商業大學,資訊與決策科學研究所、國立臺北商業大學,資料科學應用研究中心、臺北醫學大學,管理學院、臺北醫學大學,大數據研究中心、中華市場研究協會、中華資料採礦協會、國立台北科技大學,資訊與財金管理系、東吳大學,財務工程與精算數學系。

# end

2017年10月19日 星期四

by + scale 資料物件轉換為資料框並與原始資料合併




關鍵字:

  • scale 資料標準化
  • by 依群組計算
  • rbind 列合併
  • do.call 執行R函數
  • cbind 行合併

分析:

  • by 函數:提供不同群組資料執行計算. by 的結果為 list, 使用 as.data.frame 會有錯誤, 此時改用 data.frame(do.call("rbind" , x)) 即可解決此問題. 
  • scale 函數: 將資料值進行標準化轉換, (x - u)/s, u:平均值, s:標準差.
  • rbind 函數是上/下資料的列結合.
  • cbind 函數是左右資料的行結合.


R程式解說:

  • [#1] 先將 by的結果儲存成資料物件x.
  • [#2] 使用 data.frame, do.call, rbind 將by結果合併.
  • [#3] 使用 cbind 將by 結果與原有資料物件進行行合併.
  • [#4] head 函數預設顯示前6筆資料.

R程式:

x <- by(iris[-5], iris$Species, scale) # list
tmp <- data.frame(do.call("rbind", x))
iris.scale <- cbind(iris, tmp)
head(iris.scale)
# end



2017年10月8日 星期日

蒙地卡羅法估計圓周率 (Monte Carlo Estimation of pi)

# 蒙地卡羅法
# 圓周率
# 模擬
# Monte Carlo
# pi
# Simulation
# Programming
# plotrix package

分析:

  • 本範例使用蒙地卡羅法以估計圓周率 pi。
  • 考慮正方形邊長為單位1, 面積為1平方單位. 中間包括圓形, 其半徑為0.5單位,圓形面積 = pi*(0.5^2) = pi/4.
  • 在正方形內隨機產生一個點(x, y), 點落在圓型內的機率大約等於扇型面積 / 正方形面積 = pi/4。
  • 考慮(x,y)落在圓形中的次數有numberInCircle次, 全部實驗次數為N, 則 pi 大約等於:
    (numberInCircle / N ) * 4.


R程式解說:

  • [#3] 首先載入 plotrix 套件, 準備繪製圓形圖.
  • [#4] 設定亂數種子, 準備隨機產生資料點(x, y)
  • [#5] mfrow=c(1,2) 設定繪圖結果為1列2行
  • [#6] 設定 type="n" 表示不繪圖. 因後續須客製化座標軸, axes=FALSE 不繪製座標軸, asp=1設定長寬比例為1. main 標題使用 expression 以標示數學符號pi.
  • [#7] 使用 draw.circle {plotrix} 繪製圓形圖.
  • [#8] 使用 lines 繪製正外形.
  • [#9] 加上4個角落位置的座標軸.
  • [#11] 建立 pi.simulation 函數
  • [#16-18] 如果點(x, y) 與 (0.5, 0.5) 之距離小於或等於0.5, 表示此點位於圓形之內, 此時 numberInCircle 個數加上1, 繪製紅色點.
  • [#21] 點(x, y)不位於圓形內, 繪製藍色點.
  • [#23] 計算估計pi值並儲存於 c 物件.
  • [#25] 回傳估計pi值物件c.
  • [#30] 取出最後一次計算之估計pi值.
  • [#39] 使用 par 函數將繪圖結果還原成1列,1行.

蒙地卡羅法估計圓周率圖:




R程式:



# title: Monte Carlo Estiamtion of pi
# date: 2017.10.9
library(plotrix)
set.seed(123)
op <- par(mfrow=c(1,2))
plot(0.5, 0.5, xlim=c(0, 1), ylim=c(0,1), type="n", axes=FALSE, asp=1, xlab="", ylab="", main=expression(paste("Monte Carlo for ", pi)))
draw.circle(0.5, 0.5, radius=0.5)
lines(x=c(0,1,1,0,0), y=c(0,0,1,1,0))
text(c(0.05,0.95,0.95,0.05), c(0.05,0.05,0.95,0.95), c("(0,0)", "(1,0)", "(1,1)", "(0,1)"))

pi.simulation <- function(samplesize) {
 c <- rep(0, samplesize)
 numberInCircle <- 0
 for (i in 1:samplesize) {
 x <- runif(2)
 if (sqrt((x[1]-0.5)^2 + (x[2]-0.5)^2) <= 0.5) {
 numberInCircle <- numberInCircle + 1
 points(x[1], x[2], col="red", pch=".")
 }
 else {
 points(x[1], x[2], col="blue", pch=".")
 }
 c[i] <- (numberInCircle / i) * 4
 }
 return(c)
}

size <- 10000
pi.sim <- pi.simulation(size)
estimation.pi <- pi.sim[size]
text(0.5, 0.5, paste0("sample size=", size), cex=1.5)
text(0.5, 0.4, paste("pi=",estimation.pi))
plot(pi.sim, type="l", 
 main="Monte Carlo method for pi",
 xlab="samples", ylab=expression(paste("Estimation of ", pi)), 
 ylim=c(0,6))
abline(h=estimation.pi, col="red", lty=3)
grid()
par(op)
# end

2017年9月22日 星期五

R等差數列(前後二個元素相減)與條件式計算


主題: 如何計算數列的前後二個元素相減產生的新等差數列與不同條件式數值計算

# diff
# c
# lapply
# <<

分析:
  • 感謝R友 Bic Ton提供此問題
  • 考慮 x <- c(2,5,6,1,3,8,4,5,6), 計算數列中後面減前面之結果, 例: 5-2=3, 6-5=1,...., 此時可以使用 diff(x).  diff 函數預設會計算數列中第2個元素減第1個元素的結果. 參閱線上說明 ?diff 
  • 如果希望計算前面減後面之結果, 例: 2-5=33, 5-6=-1,...., 此時可以使用 -diff(x)
  • 本例考慮3種不同解法:
    (1). 使用 for 迴圈判斷等差數列每個元素為正數或負數, 再加總結果.
    (2). 使用 for 迴圈判斷等差數列每個元素為正數或負數, 將結果用 c() 向量組合成新向量, 此方法可儲存正數與負數之結果. 注意: 本方法因為要儲存新等差數列的結果, 因此執行時間須較久.
    (3). 使用 lapply 函數以進行不同條件式數值計算, 本例使用全域變數指派符號 << 以利回傳計算結果.
  • 本例第2種方法 c() 分別儲存正/負數結果, 如果資料量較大時, 例: 100萬筆資料以上, 其執行時間須很久, 此時須考量其他儲存方式, 例: 使用 list串列 以加速程式之進行.
R程式碼:

x <- c(2,5,6,1,3,8,4,5,6)
x.diff <- -diff(x)
x.diff
# method 1 using for loop
gain1 <- 0
loss1 <- 0
for (i in 1:length(x.diff)) {
 if (x.diff[i] >= 0) gain1 <- gain1 + x.diff[i]
 else if (x.diff[i] < 0) loss1 <- loss1 + x.diff[i]
}
gain1
loss1

# method 2 using for loop with c()
gain2 <- c()
loss2 <- c()
for (i in 1:length(x.diff)) {
 if (x.diff[i] >= 0) gain2 <- c(gain2, x.diff[i])
 else if (x.diff[i] < 0) loss2 <- c(loss2, x.diff[i])
}
sum(gain2)
sum(loss2)

# method 3
gain3 <- 0
loss3 <- 0
lapply(x.diff, function(x) {
 ifelse(x > 0, gain3 <<- gain3 + x, loss3 <<- loss3 + x)
 #return(c(gain, loss))
 })
gain3
loss3
# end

2017年9月10日 星期日

R讀取中文檔案產生亂碼等錯誤問題

主題: R讀取中文檔案產生亂碼等錯誤問題

說明:

# read.table
# encoding="UTF-8-BOM"
# ANSI
  • 感謝R友-阿賢提供 encoding="UTF-8-BOM"解決亂碼問題.
  • 使用R讀取文字檔時, 有時會遇到資料匯入有錯誤訊息或中文亂碼問題.
  • 資料來源: https://data.gov.tw/dataset/35131, 匯入 open data 空氣品質監測小時值(一般污染物,每日更新) 所產生的問題與解決方式.
  • 匯入資料 read.table {utils} 常用參數:
    (1). fill = TRUE --> 使用時機: 錯誤訊息為 line x did not have xxx elements.
    (2). encoding --> 結果為亂碼.
    (3). fileEncoding  --> 結果為亂碼.
  • 考慮 Windows 執行環境, 如果有亂碼問題, 最簡單的解決方式之一是使用記事本開啟檔案, 另存新檔 畫面中, 編碼改為 ANSI.


  • 使用 Notepad++ [https://notepad-plus-plus.org/zh/] 開啟檔案, 在視窗右下角狀態列會有"UTF-8-BOM"編碼, 此時可加上 encoding 或 fileEncoding 參數, 本例使用 fileEncoding = "UTF-8-BOM" 參數即可完成匯入資料.


  • 另可參考: 資料集為CSV檔,打開來為亂碼,怎麼辦? https://data.gov.tw/node/18765
  • 結論: 使用另存ANSI編碼或加入fileEncoding="UTF-8-BOM"參數應該可以解決亂碼問題.
# 執行畫面:



# R程式碼:
x1 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",") # line 1 did not have 31 elements
x2 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",", encoding="UTF-8") # line 1 did not have 31 elements
x3 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",", encoding="UTF-8", fill=TRUE) # 欄位錯誤
x3[1:3, 1:6]
x4 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",", encoding="UTF-8-BOM") # line 1 did not have 31 elements
x5 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",", encoding="UTF-8-BOM", fill=TRUE) # 亂碼
x5[1:3, 1:6]
x6 <- read.table("ATM00626_20170910170405.csv", header=TRUE, sep=",", fileEncoding = "UTF-8-BOM", fill=TRUE) # OK
x6[1:3, 1:6]
x7 <- read.table("ATM00626_20170829185638-ansi.csv", header=TRUE, sep=",") # OK
x7[1:3, 1:6]
x8 <- read.csv("ATM00626_20170910170405.csv", header=TRUE) # 亂碼
x8[1:3, 1:6]
x9 <- read.csv("ATM00626_20170910170405.csv", header=TRUE, fileEncoding = "UTF-8") # invalid input found
x10 <- read.csv("ATM00626_20170910170405.csv", header=TRUE, encoding = "UTF-8-BOM") # 亂碼
x10[1:3, 1:6]
x11 <- read.csv("ATM00626_20170910170405.csv", header=TRUE, fileEncoding = "UTF-8-BOM") # OK
x11[1:3, 1:6]
# end