:::

用HTML5開發網頁APP、桌面APP、跟行動裝置APP:混合應用程式框架 / Hybird APP Framework for Web APP, Desktop APP and Mobile APP

用HTML5開發網頁APP、桌面APP、跟行動裝置APP:混合應用程式框架 / Hybird APP Framework for Web APP, Desktop APP and Mobile APP

image

HTML5 (JavaScript + CSS3)可以在網頁上跨平臺執行已經是眾所皆知的常理,但是要如何用HTML5來開發能在瀏覽器上執行、能夠在桌面作業系統上安裝、還能夠在行動裝置(手機、平板)上安裝的應用程式呢?這個OnsenUI+Vue.js+Electron+PhoneGap Build的「混合應用程式框架」就是我的答案。

因為這只是最近心血來潮整理出來的混合做法,架構上並不是很漂亮,我也沒有打算寫太多文件。但對於想要發揮HTML5極限的開發者來說,應該是個不錯的參考。


程式碼 / Source code

image

混合應用程式框架保存在GitHub中,任何人都可以自由下載、修改、發佈。

軟體展示 / Demo

在混合應用程式框架中,我們只要開發一個HTML5框架,就可讓它以在網頁瀏覽器、桌面端應用程式、行動端應用程式執行。你可以實際玩玩看,看看混合應用程式框架會是什麼樣子:

接下來我用以下幾張截圖跟照片來讓大家看看它在不同平臺上的樣子:

網頁瀏覽器截圖 / Run in Web Browser

image

這是在Chrome網頁瀏覽器上的畫面。

Windows桌面版應用程式截圖 / Run in Windows

2018-05-24_153932

這是在Windows桌面端執行的畫面。

Android手機應用程式截圖 / Run in Android Phone

Screenshot_20180524-164945

Screenshot_20180524-164949

這是在Android手機上執行的畫面。

Android平板應用程式截圖 / Run in Android Tablet

Screenshot_20180524-165216

Screenshot_20180524-165208

這個是在Android平板 (8吋)上執行的畫面。

除了一些元件的位置怪怪的之外,大致上畫面都能夠正常呈現,很不錯吧。

接下來就讓我們來看看混合應用程式框架怎麼做到這件事情的吧。


框架架構 / Framework architecture

image

我把「混合應用程式框架」的架構整理成上面四個層次:顯示畫面 (Display)、平臺轉接(Platform Transport)、裝置(Client Device)、作業系統(Client Operation System, OS)。其中藍色的部分是我們可以掌握的元件,而灰色的部分對應不同使用者會用的客戶端。以下說明顯示畫面跟平臺轉接的細節。

顯示畫面 / Display

2018-05-24_153932

這邊使用的是Onsen UI,一個成熟的HTML5顯示框架。而控制資料邏輯的MVVM架構使用的是Vue 2。

我已經在「政大借書籃」跟「Voc4Fun全民樂單字」使用Onsen UI框架,但那時候Onsen UI只有跟Angular.js整合。現在Onsen UI已經開發到第二版,而且可以跟jQuery、Vue 2整合。

站在一個想要追求快速開發的角度,Vue算是相當好上手的MVVM架構。而這裡我選擇的是不編譯的Vue架構,因此可以直接在瀏覽器上執行,不需要任何打包或封裝。

平臺轉接 / Platform Transport

混合應用程式框架基本上可以直接用網頁瀏覽器開啟,但如果要打包成不同裝置上可以安裝的應用程式(APP),我們需要藉助一些平臺轉接的框架。

轉接桌面端應用程式:Electron / Electron for Desktop Application

Electron_0.36.4_Icon

(圖片來源:維基百科)

為了產生可以在桌面端作業系統安裝的應用程式,我們使用的是GitHub開發的知名框架Electron。

Electron可以產生給Windows、Mac OS、Linux使用的應用程式。這邊我主要只用Windows,Electron會在Windows平臺中產生可執行檔案,我寫了AutoIT將設定包裹成exe檔案,讓使用者可以直接點選執行。未來也可以更進一步使用InnoSetup打包成安裝檔。

至於Linux跟Mac OS我則沒有測試過,Linux可以直接用Electron打包,但我沒試過能不能執行。至於Mac OS,則必須要在Mac環境下打包才能使用,因此我也沒有試過。

之前我已經在「試做Electron桌面應用程式:webapp-wrapper」整理了一個簡單的基礎,現在我把它整合到混合應用程式框架中,讓Electron更容易將HTML5打包成桌面端應用程式。

轉接行動端應用程式:PhoneGap Build / PhoneGap Build for Mobile Application

Phonegap-build-mobile-app-development-tool-300x245

(圖片來源:boston technology)

為了產生可以安裝在行動裝置上的應用程式,包括手機、平板,我們使用的是PhoneGap Build。

PhoneGap Build提供了將HTML5程式打包成Android、iOS、Windows Phone三種平臺APP的功能。不過因為建構iOS APP需要具備開發者身份(每年需繳交不少費用),而Windows Phone已經沒落,所以實際上我只有用PhoneGap Build打包成Android APK而已。

我以前就有在「PhoneGap網頁樣板:簡單建立網站APP」寫過使用PhoneGap Build來建構網站APP的做法,跟Electron一樣,我也把它整合到混合應用程式框架中,成為大框架下的一份子。
值得一提的是PhoneGap Build雖然採用的是Apache Cordova核心,但這個名稱卻是描述在Adobe提供的伺服器上打包APP的整個流程,而不是像是Cordova在本機端部署環境、打包應用程式的做法。


功能 / Features

在混合應用程式框架中,我整理了一些在開發中可能會用到的功能,這是為了未來開發做的準備。這些功能包括了作為一個應用程式(APP)所需要的排版(包括主畫面、上方的工具列、左方的滑動選單)、主畫面的換頁、通知對話視窗、開啟外部連結、儲存由JSON產生的試算表檔案ODS、MVVM資料綁定、國際化語系、以遊戲引擎運作。以下簡單說明這些功能。

1. 排版與換頁 / Layout and Pages Navigation

image

混合應用程式使用了行動裝置為主的APP排版,主要畫面分成3大部分:1. 主畫面、2. 工具列 (toolbar)、3. 滑動選單 (sliding menu)。主畫面顯示該頁的主要內容,工具列會一直固定在畫面上方,而左邊的滑動選單則是會隨著你的畫面寬度動態的顯示、隱藏,你也可以按下工具列的選單按鈕來顯示滑動選單。

受益於OnsenUI的Auto Style功能,功能元件在不同平臺上會有些微的不同。舉例來說,下圖是iOS中的工具列:

image

下圖則是Android中的工具列:

image

我把換頁的方法包裝在onsenui_helper中,JavaScript語法如下:

onsenui_helper.switch_page(about)
2. 通知對話視窗 / Notification dialog

image

混合應用程式框架的使用了OnsenUI的$ons.notification功能來實作對話視窗。

受益於OnsenUI的Auto Style功能,上圖iOS風格的對話視窗在Android底下會變成下圖這個樣子:

image

通知功能的JavaScript語法如下:

vm.$ons.notification.confirm({      message: i18n.t("Are you sure to visit About?"),      callback: function (_result) {          console.log(_result);      }

});
3. 開啟外部連結 / Open link with your default browser

image

點下一些非APP內的連結時,混合應用程式框架提供了一些方法來讓他使用你預設的瀏覽器開啟。這部分我用hybird_app_helper來處理不同平臺的做法,JavaScript語法如下:

hybird_app_helper.open_window('https://github.com/pulipulichen/HTML5-Hybird-APP-Framework')
4. 儲存由JSON產生的試算表檔案ODS

image

這邊使用了JS-XLSX套件來讓JSON物件轉換成ODS試算表格式。JS-XLSX的功能複雜,網路上大部分的教學都亂七八糟,最好的用法還是官方自己提供的上傳分析轉換下載範例。我整理了JSON轉換成ODS Base64編碼的做法,寫在xlsx-helper.js檔案中。

另外的問題是如何讓裝置下載,或是說儲存、分享檔案。在網頁上,我使用的是FileSaver.js。在桌面端,我使用了Electron的ipcMain跟ipcRenderer來交換資料,讓網頁介面跟背後的Electron能夠彼此溝通,交給Electron寫入檔案。雖然Electron端已經很複雜了,但比不上在行動端的麻煩。在PhoneGap Build中,我先用cordova-plugin-file將ODS檔案寫入到cache暫存資料夾,然後使用PhoneGap / Cordova Social Sharing plugin來分享檔案。

5. MVVM資料綁定

image

混合應用程式框架使用了Vue.js的MVVM框架讓資料與顯示雙向綁定。主畫面中的「Hello, world!」綁定的是JavaScript中的「main_page.data.message」。顯示的程式設定如下:

image

而這個「main_page.data.message」則是寫在main_page.js中,資料的程式設定如下:

image

只要修改「main_page.data.message」的值,顯示畫面也會跟著改變。這是Vue.js這種MVVC框架的基本應用,相信熟悉MVVC框架的開發者應該很容易理解。

6. 國際化語系 / Localization

image

混合應用程式框架使用了javascript-i18n-core來作為語系檔的框架。以工具列中間的標題為例,我們可以用這個JavaScript語法來取得索引名稱「TITLE」的翻譯設定如下:

{{ i18n.t("TITLE") }}

語系檔放在www/locale資料夾中,裡面可以設定各個語系與對應索引名稱。

7. 以遊戲引擎運作:Cocoon.js / Game engine demo: Cocoon.js

image

為了挑戰混合應用程式框架的極限,我試著加入了Cocoon.js遊戲引擎框架所開發的兩款展示遊戲:SpaceSimDemoSuper Mario Bros

大家可以看看混合應用程式框架在網路瀏覽器、桌面端、行動裝置上玩遊戲是什麼感覺,也許未來也可以取代OnsenUI,使用Cocoon.js開發遊戲呢?


小結 / In closing

混合應用程式框架只是我為了未來可能會開發真正的跨平臺應用程式而做的一個小小的準備。我怕我現在不整理,以後可能就會忘記,所以做到這邊就趕快記錄一下。

30485967745854535578

(圖片來源:幫趣)

這整篇並沒有什麼提供給開發者的文件,請有心要使用這個框架的開發者自行trace code,程式碼都在GitHub上,請自行研讀、fork或下載吧。

開發感想 / Thoughts

接著來聊聊一些開發過程的想法。

混合應用程式框架實際上是要寫UI顯示畫面邏輯、 Electron跟桌面端底層作業系統的溝通、PhoneGap Build跟手機端底層裝置溝通的龐大架構。雖然都是用JavaScript來寫,但是不同框架下面使用的API都完全不一樣。雖然號稱跨平臺,但是還是要為不同平臺下很多功夫,實際上並沒有真的這麼跨平臺。

現在有很多開發框架是更加的跨平臺,像是Unity,但畢竟這個門檻比較高,不能直接將網頁使用的技術帶過去使用。而且對快速開發來說也不見得是比較方便。

用網頁來寫UI還是可以讓開發者有很大的自由度,特別是現在CSS3發展成熟,許多特別的UI介面又漂亮又好用,還能作出驚人的特效。我想未來我還是會繼續使用網頁來開發任何應用吧。

速度問題 / Performance issues

在開發的過程中很多人會問的是速度問題,這是PhoneGap令許多開發者詬病的問題。這個速度問題其實細分起來有兩個層面。第一個是載入,PhoneGap在開啟程式的時候,需要用「document.addEventListener("deviceready",function () {});」來確保cordova核心套件有正常載入,因此不管硬體效能多好,通常載入時間還是需要0.5秒。

image

一般來說我們會使用splash載入畫面讓使用者不會覺得太過突兀,在混合應用程式框架中也會預設使用icon.png作為載入背景畫面。

另一個問題是畫面運作時的流暢度。在Ionic Framework vs React Native Comparison這個影片中,我們可以看到基於Ionic Framework包裝的應用程式運作效能非常的差,已經到了妨礙使用體驗的程度了。但這個問題通常是因為程式寫的不好,最常見的情況,是因為開發者在轉場動畫上使用連續改變物件位置參數來營造動畫感,這卻是相當不流暢的做法。

現在比較好的做法是採用較好的顯示畫面框架,像是Onsen UI。或是根據How to Make High Performance PhoneGap Apps來修正你的程式架構。不過光是混合應用程式框架現在的架構,在各個平臺運作起來就已經很流暢了,我想就一般的應用程式來說是已經足夠使用。

如果要到玩遊戲的話,雖然看起來是可以運作Cocoon.js這種遊戲框架,但是還是不知道它的流暢度極限到底在那裡。但因為我可能比較不會朝遊戲的方向開發,這部分就待有心人士來測試吧。

其他跨平臺框架 / Cross platform framework

比起原生應用,我仍然比較偏好可以跨平臺的框架。

儘管許多知名的框架號稱自己是跨平臺,但其實也都是限制於行動裝置的平臺或桌面端的平臺,並不是真的能夠橫跨網頁、桌面端與行動裝置端,這也是我做這個混合應用程式框架的動機。
大部分的跨平臺框架有許多門檻,像是React NativeNativeScript。當然,這些門檻在混合應用框架裡面也是難以避免。

第一個門檻是編譯。幾乎現在主流的跨平臺框架都需要先進行編譯,然後才能展示最後的成果。只要框架使用了作業系統上的原生UI,幾乎都需要編譯後才能使用。React Native提供了Hot Reloading減少重複編譯的問題,但是還是需要部屬相關的編譯環境。相較之下,混合應用程式框架藉助了Adobe PhoneGab Build來編譯行動端的應用程式,我們只要用Git或壓縮成zip上傳即可,部屬環境不需要煩惱。但是如果要用Electron編譯成桌面端應用程式,那還是要用npm來安裝Electron需要的環境。Electron編譯環境所需要的指令請看README說明

第二個門檻是API。雖然框架提供了跨平臺都能使用的UI API,像是特定的按鈕、特定的工具列寫法,但這個框架的API常常已經有別於傳統網頁的做法,並非一般網頁開發者所謂的HTML5,幾乎等於你要重學一個語言。而這語言使用的API並不能帶到其他平臺上,像是網頁或桌面端的Electron,因此不能說是真的跨平臺。儘管混合應用框架本身也用了OnsenUI跟Vue.js等框架,讓人需要重新學習這些框架的用法。不過至少OnsenUI上所寫的工具列是真的可以在網頁、桌面端跟行動端正常顯示,而不會被原生UI的限制所綁架。

Electron的限制 / Huge file from Electron

相較於行動裝置端有許多大紅大紫的知名跨平臺框架,桌面端的跨平臺框架倒是只有Electron比較知名。混合應用程式框架也是使用Electron來實作桌面端應用程式的跨平臺開發。

然而,Electron最大的問題,還是它編譯出來的檔案大小實在是太大了。在www中的主要程式其實只有16MB左右,但混合應用程式框架最後編譯出來的檔案大小居然來到136MB,壓縮成7z也還有35MB之多。網路上有許多人對Electron檔案大小感到疑惑,Expected app bundle size?  中zcbenz說就是這樣大小,沒辦法。我也覺得很無奈。

剛好今天看到了新的桌面端跨平臺框架出現:Vuido,這是用Vue.js撰寫桌面端應用程式的框架,可以使用桌面端原生的UI元件,而不是像我使用混合應用框架中實際上是寫一個網頁來模擬UI介面的做法。檔案大小似乎比Electron還要小,速度上也應該會比Electron還要快吧。不過我個人還是比較喜歡寫網頁,用網頁做UI介面,因此應該不會選擇這個方案,還是繼續使用Electron吧。


好啦,混合應用程式框架就聊到這邊了。

你有想過要開發跨平臺的應用程式嗎?以前你都是怎麼做的呢?除了像混合應用程式框架使用的OnsenUI + Vue.js + Electron + PhoneGap Build之外,你還知道什麼不錯的框架嗎?對混合應用程式框架什麼問題的話,歡迎你在下面的留言發問。如果你也覺得混合應用程式框架是個開發跨平臺應用程式不錯的起點,請幫我在AddThis分享工具按讚、將這篇分享到Facebook等社群媒體吧!感謝你的耐心閱讀,讓我們下一篇見。

(more...)

怎麼將SVG向量圖插入到Word中?開放格式與專有格式的轉換 / How to insert SVG vector images into Word? Convert between Open Format and Proprietary Format

怎麼將SVG向量圖插入到Word中?開放格式與專有格式的轉換 / How to insert SVG vector images into Word? Convert between Open Format and Proprietary Format

image

前一篇我們介紹了如何將Word中使用的EMF向量圖片轉換成開放格式的SVG向量圖,這篇我們來反過來談談如何將開放格式SVG向量圖用在Word上。簡單來說,這個做法就是使用Inkscape開啟SVG向量圖,再轉存成EMF格式,這樣就可插入到Word中以向量模式運作了。最後我會整理一下SVG向量圖、EMF微軟專用向量圖、高解析度PNG圖片檔之間轉換的做法與用途,希望讓大家能夠更順利在辦公室軟體中使用向量圖片。

(more...)

EMF圖檔怎麼用?微軟專用向量圖EMF轉開放向量圖SVG教學 / How to convert EMF to SVG format

EMF圖檔怎麼用?微軟專用向量圖EMF轉開放向量圖SVG教學 / How to convert EMF to SVG format

image

EMF的全名是Enhanced Metafile,翻譯做Windows增強中繼檔,這是一種微軟專用的向量圖檔案,其目的是為了取代較早期32位元的WMF格式(Windows Metafile,Windows中繼檔)。EMF在Office軟體中能以無鋸齒的向量模式運作,但是它卻很難以高解析度的模式匯出成其他格式的圖片,令人難以使用。站在支持開放格式的立場,我這篇將教你如何將微軟專用的EMF向量圖轉換成開放格式的SVG格式,以便後續再進行編輯或轉換成高解析度的PNG圖檔。這篇教學是在Windows 7環境下使用Word 2013與InkScape來完成整個轉換動作,請確定你有這些環境才能做到本篇教的EMF轉SVG喔。

(more...)

用Acrobat Pro將掃描圖片檔案建立成PDF電子書 / Create an eBook PDF with Adobe Pro

用Acrobat Pro將掃描圖片檔案建立成PDF電子書 / Create an eBook PDF with Adobe Pro

image

我在「不拆書的自烹PDF電子書:免費軟體Scan Tailor的方案」中介紹了以Scan Tailor、XnView MP來整理掃描的電子檔,然後用一些免費工具來製作PDF檔案。但是如果你電腦裡面有安裝Acrobat Pro的話(不是免費的Adobe Reader喔),那不妨也可使用以下方法來製作PDF電子書喔。這篇將接續「不拆書的自烹PDF電子書:免費軟體Scan Tailor的方案」中Phase 3之後,後續改以Adboe Acrobat Pro DC為例介紹如何操作。

(more...)

PDF的文字錯誤怎麼辦?修正PDF上錯誤的OCR文字 / How to perform OCR PDF with Renderable Text Error

PDF的文字錯誤怎麼辦?修正PDF上錯誤的OCR文字 / How to perform OCR PDF with Renderable Text Error

image

雖然PDF檔案是標準格式,但是隨著PDF檔案產生的方法不同、文字辨識OCR工具帶來的字型與編碼問題,很多早期的PDF檔案雖然可以選取、複製文件上的文字,但複製出來的文字卻會是亂碼。我參考了Grant Robertson的建議,將PDF輸出到XPS印表機,再將XPS輸出成PDF,這樣就可以在PDF上進行OCR辨識,最後就能得到正確辨識的檔案了。以下我就來整理這一套做法,供大家參考參考。

(more...)

直接執行Python腳本:Python Caller / Running a Python Script Directly in Windows: Python Caller

直接執行Python腳本:Python Caller / Running a Python Script Directly in Windows: Python Caller

image

繼前一篇的RScript Caller之後,這次要來介紹的是直接執行Python的Python Caller。這隻程式的主要目的是提供讓Python腳本檔案(副檔名為.py)直接關聯到Python-Caller.exe,這樣就能在檔案總管中點兩下直接執行,然後在執行完畢後暫停,讓開發者可以看看執行結果。以下就是Python Caller的下載、設定與使用介紹。因為做法跟RScript Caller蠻像的,所以兩篇內容會看起來很像就是了。

(more...)

直接執行R腳本:RScript Caller / Running a R Script Directly in Windows: RScript Caller

布丁布丁吃布丁

直接執行R腳本:RScript Caller / Running a R Script Directly in Windows: RScript Caller

image

以往要使用R腳本(RScript)的時候,我都是將R腳本用RStudio開啟,再用RStudio執行。但這樣子執行挺麻煩的,也不太直覺。所以我用AutoIT開發了一個直接用指令端呼叫R腳本的exe程式:RScript Caller,方便供Windows使用。這樣我們在檔案總管中直接雙擊R腳本就可以執行R腳本的內容。以下我就來介紹一下怎麼取得RScript Caller、設定與使用吧。

(more...)

將Google試算表的圖表匯出成SVG向量圖檔 / Guide to Export Charts in Google Spreadsheet

將Google試算表的圖表匯出成SVG向量圖檔 / Guide to Export Charts in Google Spreadsheet

image23

如何從Google文件中的繪圖匯出高解析度的圖片之後,這篇要來講怎麽將Google試算表中的圖表輸出成SVG向量圖檔,以便轉換成高解析度的PNG圖片。雖然Google試算表的圖表可以輕易跟Google Docs結合,但很遺憾的是,它跟Google Docs中的繪圖一樣只能輸出72dpi的低解析度圖片,遠不及列印所需的高解析度300dpi,最後列印的時候將會看起來非常模糊。這篇將教你如何將Google試算表變成發佈網頁,然後再用我寫的書籤小工具Google-Spreadsheet-Chart-to-SVG將網頁上的圖表轉換成SVG並直接下載,這樣就可以取得圖表的SVG向量格式檔案了。

(more...)

將向量圖檔SVG轉換成高解析度的PNG圖檔:Inkscape教學 / How to Convert SVG to High-Resolution PNG Image with Inkscape?

將向量圖檔SVG轉換成高解析度的PNG圖檔:Inkscape教學 / How to Convert SVG to High-Resolution PNG Image with Inkscape?

image3

SVG可縮放向量圖形是向量圖片檔案中的一個常見標準。它具有向量圖片最大的優勢:不管圖片放到多大,字體和線條依然看起來非常清晰。許多工具都能繪製SVG圖檔,像是開放原始碼自由軟體InkscapeGoogle Docs的繪圖(Drawing),但很遺憾的是,我們現在常見的文書編輯工具(特別是Office)卻不能直接插入SVG檔案。因此,我們需要將SVG檔案轉換成高解析度的PNG圖檔,這樣才能將圖片順利插入到文件檔案中與其他文字共同排版,以便列印輸出。以下我們就用Inkscape這套專業的向量圖片編輯工具作為例子,教大家如何將SVG向量圖檔輸出成高解析度的PNG圖檔吧。

(more...)

如何從Google文件中的繪圖匯出高解析度的圖片 / Get High-Resolution Images from Drawing in Google Docs

如何從Google文件中的繪圖匯出高解析度的圖片 / Get High-Resolution Images from Drawing in Google Docs

image

我現在常常會在Google Docs (Google文件)上編輯文件,不僅方便與其他人協同作業,Google Docs內建的一些功能也足夠讓我寫入想要的內容,包括繪圖功能(Drawing)。然而Google Docs中使用繪圖功能畫出來的圖片,通常在下載成其他格式的檔案、發佈到網頁上的時候會有問題,特別是繪圖功能儘管是向量圖片,但卻預設是以72dpi的低解析度來呈現圖片,因此列印繪圖功能繪製的圖片時,看起總是慘不忍睹。

若要從Google Docs的低解析度繪圖中取得高解析度的圖片,我們需要將繪圖另存成SVG,然後使用InkScape之類的SVG編輯器來匯出高解析度的圖片。以下我就將這個方法整理一下,希望對與Google Docs使用者有所幫助。

(more...)

多組常態分佈資料之差異檢定與事後比較:R的ANOVA與Welch's anova / Parametric Tests for Comparing Many Normal Distribution Groups: ANOVA and Welch's anova in R

布丁布丁吃布丁

多組常態分佈資料之差異檢定與事後比較:R的ANOVA與Welch's anova / Parametric Tests for Comparing Many Normal Distribution Groups: ANOVA and Welch's anova in R

image

繼前一篇用的Kruskal–Wallis檢定跟Welch's anova來檢定多組非常態分佈資料之間是否有差異的無母數統計之後,這一篇則是用於常態分佈的多組資料之間差異檢定的有母數統計,也就是大家比較熟悉的ANOVA。雖然ANOVA也可以用SPSS來操作,不過這篇用R腳本來實作,不僅自動進行敘述統計、繪製直方圖與箱型圖,還會根據資料同質性檢定結果選擇使用ANOVA或Welch's ANOVA,操作起來更簡單喔。

(more...)

多組非常態分佈資料之差異檢定與事後比較:R的Kruskal–Wallis檢定與Welch's anova / Non-Parametric Tests for Comparing Many Non-normal Distribution Groups: Kruskal–Wallis test and Welch's anova in R

布丁布丁吃布丁

多組非常態分佈資料之差異檢定與事後比較:R的Kruskal–Wallis檢定與Welch's anova / Non-Parametric Tests for Comparing Many Non-normal Distribution Groups: Kruskal–Wallis test and Welch's anova in R

image

很多時候我們研究的資料不一定符合常態分佈,例如車禍數量的趨勢符合泊松分佈(Poisson distribution)、產品的生命週期符合韋伯分佈(Weibull distribution),甚至是健康、教育和社會科學中最常見的出現次數(frequency of appearance)這種研究資料都不是常態分佈(請見Bono等人在2017年的回顧文章)。

當要比較的多組資料為常態分佈時,我們可以用單因子變異數(one-way ANOVA)。但若多組資料並非常態分佈時,我們則要使用中位數的ANOVA:Kruskal–Wallis檢定以及事後比較Dunn檢定。而若各組資料之間變異數不同質時,則要用Welch's anova跟事後比較Games-Howell檢定。

為了方便使用,我將多組非常態分佈資料檢定的方法以R撰寫成一個腳本Non-Parametric Tests for Comparing Many Non-normal Distribution Groups.R供大家使用。以下將介紹如何使用這個腳本來進行多組非常態分佈的差異檢定。

非常態分佈的資料 / Non-normal distribution data

在健康、教育和社會科學等領域的研究中所蒐集的資料,很多時候都是非常態分佈。Non-Normal Distributions in the Real World介紹了非常態分佈的常見資料,像是人類的行為模式,例如收到發貨單跟付款之間的差距天數,或是受到物理法則影響的資料,像是鍍鋅厚度的分佈。

How do I determine whether my data are normal?這篇講述了四種判斷資料是否為常態分佈的方法,摘要如下:

  • 觀察疊加了常態分佈曲線(normal curve)的直方圖(histogram),看資料是否非常偏離常態分佈曲線。
  • 觀察偏態值(Skewness)是否遠離0。0表示為常態分佈。
  • 使用常態分佈檢定Kolmogorov-Smirnov test (K-S)與Shapiro-Wilk (S-W)檢定。
  • 使用「常態分位圖」(Normal Q-Q Plot),觀看資料是否落於常態分佈線上。

有時候資料可能會是常態分佈,但因為某些問題導致它看起來是非常態分佈。Statistics How To的Non Normal Distribution歸納了四個可能會讓資料呈現非常態分佈的理由:

  1. 資料包含異常值(outliers):如果資料包含了異常值,則資料分佈會變成偏態(skewed)。有母數統計的核心平均數(mean)特別容易收到異常值的影響。移除異常值之後再來分析看看。
  2. 資料分佈是由多組常態分佈的資料組成:這會造成雙峰(bimodal)或多峰(multimodal)的分佈。例如,下圖包含了兩組常態分佈的測試結果,這讓資料呈現了雙峰分佈。
    bimodal-distribution-2
    (圖片來源:Statistics How To)
  3. 資料不足:如果資料數量不夠大,則會讓常態分佈的資料看起來完全分散。舉例來說,課堂測驗結果一般是常態分佈。如果我們用極端的例子來看,只隨機抽取三位學生並將之繪製統計圖表,則結果並不會是常態分佈。可能會是得到均勻分佈(uniform distribution),如62、62、63;也可能會得到偏態分佈,例如80、92、99。蒐集更多資料再來分析看看吧。
  4. 錯誤的統計圖表誤導。通常是X軸或Y軸的單位、區間設定錯誤,導致直方圖出現偏態。請確認直方圖正確的繪製再來分析資料吧。

若你的資料確實是非常態分佈,那麼你可能需要用這篇的方法來分析這些資料。


    R腳本與執行環境 / R script and environment

    image

    R腳本必須要在有R的環境下執行。我個人使用的是在Windows上執行的RStudio,版本是1.1.383。在安裝RStudio的時候會一同安裝R環境。我使用的R的版本是3.4,此外還會用到多個套件,套件的安裝全部寫在R的腳本裡。

    此腳本主要改編自An R Companion for the Handbook of Biological Statistics的Kruskal–Wallis Test,後面加上的Welch's anova則是來自於同網站的One-way Anova,事後多重比較Games-Howell檢定則是來自於RPubs

    因為R的版本更新的非常頻繁,你閱讀這篇的時候安裝的不一定是跟我一樣的R 3.4版,可能會有版本差異的問題。若安裝套件時發生了版本不符合的問題,請看Ubuntu中舊版R安裝套件的方法。關於R的版本問題,請看我之前學習R的感想

    參考資料 / Reference

    此腳本主要改編自An R Companion for the Handbook of Biological Statistics的Kruskal–Wallis Test,後面加上的Welch's anova則是來自於同網站的One-way Anova,事後多重比較Games-Howell檢定則是來自於RPubs

    至於Kruskal–Wallis檢定的理論基礎請見John H. McDonald所著的Kruskal–Wallis test,裡面介紹了Kruskal–Wallis檢定的適用時機以及與它與單因子變異數的差別,該篇也建議Kruskal–Wallis檢定應該只用在排序資料上,像是社會科學中權力階層的上下位關係或是發展階段先後順序。Welch's anova的理論基礎請見Jim Frost所著的Benefits of Welch’s ANOVA Compared to the Classic One-Way ANOVA。大部分時候Welch's anova都是被視為當ANOVA違反變異數同質性檢定時的替代方案,但它也可以在Kruskal–Wallis檢定違反變異數同質性檢定的時候使用。


    實作:多組非常態分佈同質性資料之中位數差異檢定 / Practice: Test for difference in median among many homoscedastic groups

    Group 1 Group 2 Group 3
    1 10 19
    2 11 20
    3 12 21
    4 13 22
    5 14 23
    6 15 24
    7 16 25
    8 17 26
    9 18 27
    46 37 28
    47 58 65
    48 59 66
    49 60 67
    50 61 68
    51 62 69
    52 63 70
    53 64 71
    342 193 72

    (表格來源:Handbook of Biological Statistics)

    以下我用John H. McDonald在介紹Kruskal–Wallis檢定的時候使用的資料作為例子,以此來示範如何使用R腳本Non-Parametric Tests for Comparing Many Non-normal Distribution Groups.R來進行Kruskal–Wallis檢定。

    資料格式 / Data format

    image

    R腳本需要輸入的資料必須是CSV格式,以逗點(,)隔開欄位,而第一行必須是group value ,group欄位擺放組別名稱,value欄位則是擺放數字資料。請務必依照這個格式來建立資料,這樣才能用在R腳本中。

    image

    請下載CSV格式,待會兒就來使用。

    執行R腳本 / Excute R script

    image

    請在Non-Parametric Tests for Comparing Many Non-normal Distribution Groups.R檔案按右鍵,在右鍵選單中的「開啟檔案」點選RStudio。

    image

    接著RStudio會開啟並載入R腳本。我們在腳本的位置按熱鍵Ctrl + A全選腳本文字,然後按下上方的「Run」按鈕。

    image

    選擇剛剛下載的CSV檔案,然後按下「開啟」。

    image

    如果是第一次執行,R環境需要安裝大量的套件,大概會花個10分鐘左右,請耐心等候。第二次執行的時候,大概30秒內可以完成。最後看到左下角的Console有出現「Finish」就表示執行完成。

    image

    在CSV檔案的目錄底下會出現以CSV檔案為名、並加上日期時間與輸出資料後綴的統計結果檔案,包括:

    • 直方圖(histogram):檔案名稱例子為Kruskal–Wallis test example - data_0127-2042_ histogram.png
    • 箱型圖(boxplot):檔案名稱例子為Kruskal–Wallis test example - data_0127-2042_ boxplot.png
    • 檢定結果:Kruskal–Wallis test example - data_0127-2042_ result.txt

    以下我們以Kruskal–Wallis檢定結果檔案為主,其他兩個統計圖表為輔,來解說Kruskal–Wallis檢定結果吧。

    檢定結果 / Result

    在result.txt為後綴的檔案中記錄著分析的過程,以下我就各個段落進行解說:

    檔案名稱 / File
    ### File: 
    C:\data\Kruskal–Wallis test example - data.csv

    記錄該結果是來自於那個檔案。

    敘述統計 / Descriptive statistics
    ### Medians and descriptive statistics

       group  n mean       sd min    Q1 median    Q3 max
    1     A 18 43.5 77.77513   1  5.25   27.5 49.75 342
    2     B 18 43.5 43.69446  10 14.25   27.5 60.75 193
    3     C 18 43.5 23.16755  19 23.25   27.5 67.75  72

    敘述統計會列出各個組別的組別名稱(group)、個數(n)、平均數(mean)、標準差(sd)、最小值(min)、下四分位數(Q1)、中位數(median)、上四分位數(Q3)、最大值(max)。就像我在資料的中心與離度所強調的,在說明敘述統計的時候,最好搭配圖表一起看。

    Kruskal–Wallis test example - data_0127-2042_histogram

    histogram.png是各組的直方圖,注意Y軸為所佔比例,而非資料的個數。從這邊可以看到A組跟B組各有一個異常值,導致這兩組的資料明顯呈現右偏。

    Kruskal–Wallis test example - data_0127-2042_boxplot

    boxplot.png是各組的箱型圖,我們可以看到三組的五數綜合比較。儘管三組的中位數都相同,但A組跟B組的離群值讓三組的資料分佈有所差異。關於箱型圖的閱讀方法,請看用R畫箱型圖

    常態性檢定 / Normality test
    ### Normality test

    Group: A, Shapiro-Wilk normality test W = 0.4856823 p-value = 6.035973e-07
    Group: B, Shapiro-Wilk normality test W = 0.6784267 p-value = 4.530191e-05
    Group: C, Shapiro-Wilk normality test W = 0.7404266 p-value = 0.0002453774

    這裡測試各組的資料分佈是否為常態分佈。根據柴惠敏的建議,若該組的樣本個數小於50,則是使用Shapiro-Wilk常態檢定,檢定統計量為W值;若該組的樣本數在50以上,則是使用Kolmogorov-Smirnov (K-S)常態檢定,檢定統計量為D值。STHDA推薦使用Shapiro-Wilk檢定,因為它的統計檢定力(power)高於Kolmogorov-Smirnov檢定。這邊R腳本會依照該組的樣本個數來自動判斷要使用的檢定法。

    這兩個檢定的虛無假設都是該組資料為常態分佈。因此若p值在0.05以下,則表示該組資料並非常態分佈。以這個例子來說,A組的p值為6.035973e-07,有e表示是科學記號格式,意思是6.035973乘以-10的7次方,也就是非常非常小的小數,低於顯著水準0.05,因此A組資料並非常態分佈。另外C組的p值為0.0002453774,低於顯著水準0.05,因此也不是常態分佈。

    一般來說,無母數檢定並不會特別去檢定資料分佈是否非常態。這個常態性檢定僅供參考即可。

    變異數同質性檢定 / Test for Homogeneity of Variance
    ### Test for Homogeneity of Variance

    Levene's Test for Homogeneity of Variance (center = median)
           Df F value Pr(>F)
    group  2  0.6864  0.508
           51              

    Data are homoscedastic. Excute Kruskal–Wallis test.

    這邊我們使用Levene變異數同質性檢定中無母數檢定的方法來檢定三組的變異數是否相同。請看「Pr(>F)」這一欄的顯著性是否在0.05以上。若在0.05以上使用的是Kruskal–Wallis檢定,否則使用Welch's anova。

    在本例中,因為三組資料變異數同質,因此進行Kruskal–Wallis檢定。

    Kruskal–Wallis檢定 / Kruskal–Wallis test
    ### Kruskal–Wallis test for equal variances

       Kruskal-Wallis rank sum test

    data:  value by group
    Kruskal-Wallis chi-squared = 7.3553, df = 2, p-value = 0.02528

    Eta squared: 0.138779831861593

    檢定結果的卡方統計檢定量請看Kruskal-Wallis chi-squared,為7.3553。自由度df為2。各組之間是否有顯著差異則要看p-value,若在顯著水準0.05以上,則表示各組之間的中位數沒有顯著差異,否則表示各組之間的中位數有顯著差異。本例的p-value為0.02528,表示各組之間的中位數達到顯著差異。

    最後的Eta squared是表示分組變項group對於value的影響力,也就是關聯強度。計算方式來自於how2stats的Kruskal-Wallis - SPSS教學。關於Eta squared的說明請看我介紹ANOVA的這篇。Eta squared的判斷準則如下:

    • 0.059 > eta squared >= 0.01 低度關聯強度
    • 0.138 > eta squared >= 0.059 中度關聯強度
    • eta squared >= 0.138 高度關聯強度

    以本例的0.138779831861593為例,是屬於高度關聯強度。

    Dunn事後多重比較檢定 / Dunn Post Hoc test
    ### Dunn test

       Comparison         Z    P.unadj      P.adj
    1      A - B -1.356036 0.17508782 0.17508782
    2      A - C -2.712071 0.00668642 0.02005926
    3      B - C -1.356036 0.17508782 0.26263172

    若Kruskal–Wallis檢定有顯著差異,則繼續查看Dunn檢定的結果。Dunn檢定將各組之間兩兩比較,以此查看各組之間是否有顯著差異。本例中有三個組別「A」、「B」、「C」,因此共有「A - B」、「A - C」跟「B - C」三種組合可供比較。其中第二組比較「A - C」結果中的調整後P值(P.adj) 0.02小於0.05,而Z值為-2.712071小於0,表示後者組別「C」顯著大於前者組別「A」。而其他兩組比較則沒有顯著差異。

    這樣子就完成了Kruskal–Wallis檢定跟Dunn事後多重比較囉。


    實作:多組非常態分佈異質性資料之中位數差異檢定 / Practice: Test for difference in mean among many heteroscedastic groups

    許多使用Kruskal–Wallis檢定的研究者常常忘記Kruskal–Wallis檢定有各組資料為同質性的假設。當各組的個數相同,或是分佈類似時,各組資料常常具有同質性(homoscedastic)。但若各組的樣本數差異過大時,很容易就會發生各組資料為異質性(heteroscedastic)的情況,這時候就要改用Welch's anova來分析。我寫的R腳本中會以無母數的Levene檢定來做各組資料是否為同質性的檢定,以此來判斷要選擇用Kruskal–Wallis檢定還是Welch's anova。以下我們就來看看這種情況會怎麼分析。

    異質性的資料 / Heteroscedastic data

    image

    這份資料是來自於Real Statistics Using Excel的Welch's ANOVA Test的例子。我們的格式也一樣要有group跟value,然後請下載CSV格式做準備吧。

    image

    待會會使用這個CSV檔案來分析。

    執行R腳本 / Excute R script

    image

    操作方法跟上述相同,在此我們就不贅述。若順利分析完成,最後一樣可以獲得三個檔案:

    • 直方圖:Welchs ANOVA Test example - data_0128-1514_ histogram.png
    • 箱型圖:Welchs ANOVA Test example - data_0128-1514_boxplot.png
    • 檢定結果:Welchs ANOVA Test example - data_0128-1514_ result.txt

    以下我們依然是來從檢定結果檔案來說明分析的結果吧。

    檢定結果 / Result

    在result.txt為後綴的檔案中記錄著分析的過程,以下我就各個段落進行解說:

    檔案名稱 / File
    ### File

    C:\data\Welchs ANOVA Test - data.csv

    這是本次分析的檔案。

    敘述統計 / Descriptive statistics
    ### Medians and descriptive statistics

         group  n     mean        sd min    Q1 median    Q3 max
    1     New 10 43.00000  4.027682  38 40.25     42 44.75  50
    2     Old  9 33.44444  9.302031  22 27.00     31 40.00  50
    3 Control  8 35.75000 16.298554  16 22.75     34 46.75  60

    敘述統計中可以看到這次的資料有三組「New」、「Old」跟「Control」,三組的個數(n)、平均數(mean)、標準差(sd)都不一樣。

    Welchs ANOVA Test example - data_0128-1514_histogram

    在以histogram.png後綴的直方圖裡面可以看到三組的分佈。Control的分佈較廣,Old的資料偏小且分散,而New的資料則較大且集中。

    Welchs ANOVA Test example - data_0128-1514_boxplot

    在以boxplot.png後綴的箱型圖裡面可以清楚比較三組的分佈。可以看到New大部分都大於Old,而Control則是涵蓋前兩組。

    常態性檢定 / Normality test
    ### Normality test

    Group: New, Shapiro-Wilk normality test W = 0.9239325 p-value = 0.3909235
    Group: Old, Shapiro-Wilk normality test W = 0.9327685 p-value = 0.5081456
    Group: Control, Shapiro-Wilk normality test W = 0.9419088 p-value = 0.6299536

    常態性檢定中,因為各組資料個數都小於50,因此使用的是Shapiro-Wilk檢定。三組的p值都大於顯著水準0.05,表示三組皆為常態分佈。因為這個例子是用來跟有母數統計ANOVA做對比用,因此資料本身是為常態分佈。

    變異數同質性檢定 / Test for Homogeneity of Variance
    ### Test for Homogeneity of Variance

    Levene's Test for Homogeneity of Variance (center = median)
           Df F value   Pr(>F)  
    group  2  6.5194 0.005478 **
           24                   
    ---
    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

    Data are heteroscedastic. Excute Welch's anova.

    在Levene檢定中,Pr(>F)的數值0.005478小於顯著水準0.05,表示各組資料為異質性,因此接下來將使用Welch's anova進行分析。

    Welch's anova
    ### Welch’s anova for unequal variances

       One-way analysis of means (not assuming equal variances)

    data:  value and group
    F = 4.3153, num df = 2.0, denom df = 11.7, p-value = 0.03947

    在Welch's anova中檢定的是各組的平均數是否相同,檢定統計量F值為4.3153,而顯著性p值(p-value)為0.03947,小於顯著水準0.05,表示三組資料之間有顯著差異。

    Games-Howell事後多重比較 / Games-Howell Post-Hoc Test
    ### Games-Howell Post-Hoc Test

    ### Oneway Anova for y=value and x=group (groups: New, Old, Control)

    Omega squared: 95% CI = [NA; .36], point estimate = .08
    Eta Squared: 95% CI = [0; .32], point estimate = .15

                                          SS Df     MS    F    p
    Between groups (error + effect)  474.28  2 237.14 2.11 .143
    Within groups (error only)      2697.72 24 112.41         


    ### Post hoc test: games-howell

                  diff  ci.lo ci.hi    t    df    p
    Old-New     -9.56 -18.65 -0.46 2.85 10.66 .040
    Control-New -7.25 -24.26  9.76 1.23  7.69 .472
    Control-Old  2.31 -15.41 20.02 0.35 10.84 .934

    Eta Squared的點估計值為0.15,表示高度關聯強度。然後我們看「### Post hoc test: games-howell」以下的部分,可以看到「Old」、「New」、「Control」三組的比較結果。

    在「Old-New」的比較中,p值(p)為0.04,小於顯著水準0.05,而diff為-9.56,表示前者「Old」比後者「New」還小。另一方面,「Control-New」跟「Control-Old」的比較中,p值都超過0.05,表示兩組比較沒有顯著差異。

    這樣子就完成了Welch's anova跟Games-Howell事後多重比較囉。


    結語 / Conclusion

    本篇以R腳本實作了Kruskal–Wallis檢定跟Dunn事後多重比較以及Welch's anova跟Games-Howell事後多重比較這兩套無母數統計方法,可以用來分析非常態分佈的多組資料之間是否有顯著差異。這個方法整理完之後,應該可以對社會科學、行為研究帶來很大的幫助。

    我本來是想要用SPSS來完成這個分析,但看了最完整的how2stats的Kruskal-Wallis - SPSS教學後,發現它不僅操作起來非常複雜,而且也只實作了最基本的Kruskal–Wallis檢定,更別說變異數同質性檢定、常態分佈檢定、直方圖跟箱型圖的繪製等等。後來我看了幾篇用R實作的教學,發現R做起來不僅容易許多,而且輸出資料也很容易客製化,甚至要用Kruskal–Wallis檢定還是Welch's anova也都可以用程式判斷,所以這次我就把它整理成更好用的R腳本,提供給大家使用。這次的R腳本比上次在做循序樣式探勘的時候進步許多,蠻接近我理想中的R的用法。

    這篇在撰寫的時候,本來只有Kruskal–Wallis檢定跟Dunn事後多重比較,但很多文獻提到了非同質性時的處理方法,又有在講資料是否為常態分佈的檢定,我就一邊看一邊加入各種功能,最後花了兩天的時間才整理完這份R腳本以及這篇教學,花的時間意外的多了很多。

    之後有時間的話我也想依照這份腳本做成一份ANOVA分析用的R腳本,同時也將資料違反同質性假設(是異質性)的時候改用Welch's anova的方法也納入考量,這樣應該會讓ANOVA好用許多。


    這篇多組非常態分佈資料的差異檢定的整理就到這裡為止。我本身並非統計專業,只是因為分析資料時會用到,所以看文獻來將它整理一下。如果有什麼統計上的建議,歡迎在下面留言提出指教。當你分析的資料也是非常態分佈的時候,那這篇應該會對你有些幫助。如果你覺得我整理的不錯的話,請幫我在AddThis分享工具按讚、將這篇分享到Facebook等社群媒體吧!感謝你的耐心閱讀,讓我們下一篇見。

    (more...)

    精靈寶可夢GO的VIP團體戰日期已經可以預測了?8-7-7-8循環週期 / Pokemon Go's EX Raid schedule and future dates speculation seems confirmed!

    布丁布丁吃布丁

    精靈寶可夢GO的VIP團體戰日期已經可以預測了?8-7-7-8循環週期 / Pokemon Go's EX Raid schedule and future dates speculation seems confirmed!

    image

    繼之前的「VIP團體戰舉行規則彙整」之後,國外的精靈寶可夢GO社群網站Pokemon GO Hub又進一步整理出VIP團體戰(EX Raid)的舉行週期!簡單來說大致上是以8-7-7-8的天數間隔循環,而收到VIP團體戰邀請函後則大概是9-8-8-9天後舉行。如果玩家想要追超夢,又怕卡到自己未來行程的話,不妨考慮一下這篇所介紹的VIP團體戰舉行週期喔。以下我試著將該篇內容翻譯跟大家分享,為了對應臺灣玩家的時區,日期部分我參考實際臺灣地區的時間做調整。

    (圖片來源:Pokemon GO Hub)

    (more...)

    超夢券不再是作夢?VIP團體戰舉行規則彙整 / A comprehensive guide on how to trigger EX Raids

    布丁布丁吃布丁

    超夢券不再是作夢?VIP團體戰舉行規則彙整 / A comprehensive guide on how to trigger EX Raids

    image

    (圖片來源:Pokémon GO)

    這是來自於GO HUB上的教學「A comprehensive guide on how to trigger EX Raids」,教導精靈寶可夢GO玩家如何開啟你所在位置的VIP團體戰(EX Raids),進而有機會拿到VIP團體戰入場券、並挑戰現在的VIP團體戰頭目:超夢。有在關注精靈寶可夢GO的玩家應該都已經知道VIP團體戰的已公開規則就是「地點:贊助商、公園」、「道館聲望:金牌」、「活動:團體戰」,但對於團體戰的開啟條件與規律多在玩家間經驗歸納,尚無較有系統性的整理。

    這篇教學則更深入的研究了S2地理網格 (S2 cells)、道館資格(gym eligibility)、最低參與玩家人數(expected player)以及團體戰活動(raiding activity)等細節,我覺得對玩家來說蠻有啟發意義,所以花點時間來翻譯看看,並依據臺灣的狀況調整一些教學細節,最後再加入一些我個人的觀察。

    當然,這篇教學依然只是玩家歸納的規則,而這之中依然包含了大量的隨機要素,並非100%準確。遊戲官方Niantic仍然會對VIP團體戰的規則進行調整,因此玩家把這篇當作參考即可。開心遊戲最重要喔!

    (more...)

    找出你關注的隱含知識:以Cortana做子群組探勘 / Discovery Knowledge in Your Interesting Target: Subgroup Discovery with CORTANA

    布丁布丁吃布丁

    找出你關注的隱含知識:以Cortana做子群組探勘 / Discovery Knowledge in Your Interesting Target: Subgroup Discovery with CORTANA

    image

    聚焦於你感興趣的關聯規則:Weka的HotSpot演算法之後,這篇要介紹的是實作了Exceptional Model Mining的子社群探勘(subgroup discovery)專門工具:CORTANA。跟HotSpot相比,CORTANA不僅可以探勘連續類型的目標變項(target variable),還能夠綜合多個目標變項成為一個目標概念(target concept),以此找到最能符合目標概念的子群組(subgroup)。

    (more...)