how to add libraries for a NetBeans project

如何為 NetBeans 專案添加類別庫,下面以添加 Apache Commons-CSV 讀取CSV檔案的類別庫為例。

下載及解開 Apache Commons-CSV 類別庫
    URL: https://commons.apache.org/proper/commons-csv/download_csv.cgi
	     點選 Binaries/commons-csv-1.10.0-bin.zip
    解壓後路徑: C:\...\commons-csv-1.10.0 

從 NetBeans 左欄面板,如下點選填入名稱,類別檔,原始碼,註解檔路徑。
Projects/Project Name/Libraries/Add Library.../Create
	Library Name: Commons-CSV
	Library Type: Class Libraries

	Classpath/Library Classpath: 類別檔路徑
		Add JAR/Folder...
		C:\...\commons-csv-1.10.0\commons-csv-1.10.0.jar

	Sources/Library Sources: 原始碼路徑
		Add JAR/Folder...
		C:\...\commons-csv-1.10.0\commons-csv-1.10.0-sources.jar

	Javadoc/Library Javadoc: 註解檔路徑
		Add JAR/Folder...
		C:\...\commons-csv-1.10.0\apidocs

設定類別檔,原始碼,註解檔的完整路徑,安裝類別庫之後,NetBeans專案就可以使用如下類別庫套件:
  org.apache.commons.csv.*

遇到有疑問的類別或方法,可選擇其名字,按如下選單或快速鍵,查看其註解或原始碼:
看註解: Source/Show Documentation (Ctrl-Shift-Space)
看原始碼: Navigate/Go to Source (Ctrl-Shift-B)

why thrashing occurs in virtual memory systems

依據現代電腦的馮紐曼運算架構,CPU始終只能從記憶體讀取資料執行,不能直接從硬碟讀取資料。因此,程式常受限於記憶體的容量限制而無法載入執行。可是明明電腦系統的硬碟容量常是記憶體的上千倍,難道不能克服困難,將硬碟當成記憶體使用嗎?

虛擬記憶體 (Virtual Memory)就是這樣一個應急措施,可將硬碟分一塊置換空間 (Swap Space),當成記憶體用。其明顯好處是從此電腦不再受記憶體的容量限制,再大、再多的程式也可執行。只要硬碟夠大,頂多暫時存放在硬碟的置換空間,要用時再搬進記憶體執行即可。

但記住虛擬記憶體始終只是一個應急措施,不能當成常態使用。理由是資料在記憶體和硬碟之間搬移 (swapping) 時,要花費很久的等候時間,互動式用戶將等的不耐煩,故只適合非不得已偶一為之。例如,記憶體的批次用戶較多,可暫時挪到硬碟休息,先讓互動用戶使用記憶體。

採用虛擬記憶體有一個副作用是如果管理不好,分配給程式的實體記憶體不夠,須要先將暫時不用的程式從記憶體搬出到硬碟 (page out),才能騰出空間,讓須要的程式碼從硬碟搬回到記憶體 (page in) 執行。萬一記憶體極端不足情況下,很可能剛搬出的程式,等下又要再搬入,造成所謂的掙扎 (thrashing) 現象。出現此反常現象時,系統效能將變極差,只見硬碟不斷亮燈,苦苦忙著將資料從記憶體搬出搬進,I/O使用率陡升,而CPU卻坐等資料搬好,閒閒沒事幹,CPU使用率陡降。

註: 上述 掙扎現象的英文 thrashing 查字典有如下諸多意思:
           http://www.merriam-webster.com/dictionary/thrash
           掙扎,輾轉,擺盪,振盪,顛簸,抖動,猛移,往復移動,頻繁置換;
           徒勞,作虛功,無進展,白費力氣,原地踏步;
           打敗,痛打,窮忙,窮打,窮追猛打
       常見直譯有 輾轉,擺盪,抖動,甚至意譯 窮忙,作虛功,也都很傳神。
       選擇 掙扎 則兼有直譯及意譯,猶如泳者奮力浮水,離水之魚奮拍入水之勢。

active versus passive multiprogramming

多元規劃 (multiprogramming) 是作業系統演進上,早期一項重要發明。早期電腦的記憶體一次只放一支程式,遇到程式執行I/O指令,等候I/O結果,CPU就閒置浪費掉。因此,利用多元規劃技術,在記憶體放進多支程式,遇程式等I/O時,就將CPU分配給其他程式使用,如此即可提升CPU使用率 (utilization)。

至於為何將技術取名為多元規劃,讓人從字面不易猜透其義? 猜測可能是參考當時流行的線性規劃 (linear programming),整數規劃 (integer programming) 等最佳化技術的命名。顧名思義,多元 指的是記憶體一次載入多支程式,規劃 指的是安排多支程式執行。而某種意義上,這也的確是讓CPU使用率提升的一種最佳化技術。如果對多元用語的語義不明有芥蒂,也許稱為 多程式規劃 會更一目暸然。一個電腦系統的 多元規劃度 (degree of multiprogramming) 為記憶體可放進多少支程式的數量,其值越高,表示CPU有越多程式可執行,越有利於提升CPU使用率。

多元規劃依據作業系統排班器對CPU掌控程度分為兩種。主動式多元規劃 (active multiprogramming) 利用計時器中斷主動介入, 給定時間一到,CPU即須讓出跑其他程式,可防止CPU遭程式霸佔;被動式多元規劃 (passive multiprogramming) 的排班器只能被動等候程式志願退出,或作I/O,或收到外部週邊中斷,才能重新取得CPU分配給其他程式,容易造成CPU遭程式霸佔。 

how to solve the tower of hanoi by recursion versus simulated call stack?


/*
   TowerOfHanoi.java  遞迴版 及 模擬呼叫堆疊版 求解河內塔 

> java TowerOfHanoi
Hanoi Tower by Implicit Call Stack 遞迴版
A:[3, 2, 1], B:[], C:[]		1: Move disk 1 from A to C
        A:[3, 2], B:[], C:[1]		2: Move disk 2 from A to B
        A:[3], B:[2], C:[1]		3: Move disk 1 from C to B
A:[3], B:[2, 1], C:[]		4: Move disk 3 from A to C
A:[], B:[2, 1], C:[3]		5: Move disk 1 from B to A
        A:[1], B:[2], C:[3]		6: Move disk 2 from B to C
        A:[1], B:[], C:[3, 2]		7: Move disk 1 from A to C
A:[], B:[], C:[3, 2, 1]

Hanoi Tower by Explicit Stack 模擬呼叫堆疊版
A:[3, 2, 1], B:[], C:[]		1: Move disk 1 from A to C
        A:[3, 2], B:[], C:[1]		2: Move disk 2 from A to B
        A:[3], B:[2], C:[1]		3: Move disk 1 from C to B
A:[3], B:[2, 1], C:[]		4: Move disk 3 from A to C
A:[], B:[2, 1], C:[3]		5: Move disk 1 from B to A
        A:[1], B:[2], C:[3]		6: Move disk 2 from B to C
        A:[1], B:[], C:[3, 2]		7: Move disk 1 from A to C
A:[], B:[], C:[3, 2, 1]
*/
import java.util.Stack;

public class TowerOfHanoi 
{
    static Stack stackA = new Stack<>();  // 柱A
    static Stack stackB = new Stack<>();  // 柱B
    static Stack stackC = new Stack<>();  // 柱C
    static int nDisks = 5; // Number of disks 盤數
    static int count = 0;  // 步數
    static boolean printGoal = false;  // 列印目標否
    static boolean printOperation = true;  // 列印步驟否
    static boolean printStack = false;  // 列印模擬呼叫堆疊否

    // 印n格空白
    public static void printSpaces(int n)
    {
        for(int i=0; i <= n -1; i++) System.out.print(" ");
    }
    
    // 印柱A,柱B,柱C堆疊,前面n層內縮
    public static void printStacks(int n)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("A:" + stackA);
        sb.append(", B:" + stackB);
        sb.append(", C:" + stackC);

        System.out.println();
        printSpaces(n*8);  // 每層內縮8格
        System.out.print(sb.toString());
    }
    
    // 搬移柱from頂一個盤子到柱to
    public static void transfer(char from, char to)
    {
        if(from=='A' && to=='B') stackB.push(stackA.pop());
        if(from=='A' && to=='C') stackC.push(stackA.pop());
        if(from=='B' && to=='A') stackA.push(stackB.pop());
        if(from=='B' && to=='C') stackC.push(stackB.pop());
        if(from=='C' && to=='A') stackA.push(stackC.pop());
        if(from=='C' && to=='B') stackB.push(stackC.pop());
    }
    
    // 遞迴版解河內塔,將n個盤子從柱sourc,搬到柱target,透過柱auxiliary
    public static void solveHanoi(int n, char source, char auxiliary, char target) 
    {        
        if(printGoal) 
        {
            System.out.println();
            printSpaces((nDisks - n)*8);
            System.out.print(String.format("hanoi(n:%d,s:%c -> t:%c)",n,source,target));
        }

        if (n == 1) 
        {
            if(printOperation) 
                System.out.print(String.format("\t\t%d: Move disk 1 from %c to %c", ++count, source, target));

            transfer(source, target);            
        } 
        else 
        {
            solveHanoi(n - 1, source, target, auxiliary);

            printStacks(nDisks - n);            
            if(printOperation) 
                System.out.print(String.format("\t\t%d: Move disk %d from %c to %c", ++count, n, source, target));
            transfer(source, target);
            printStacks(nDisks - n);

            solveHanoi(n - 1, auxiliary, source, target);
        }
    }

    // 模擬呼叫記錄    
    static class HanoiCallRecord
    {
        int num;
        char source;
        char auxiliary;
        char target;
        int stage; // 0 for moving n-1 disks from source to auxiliary rods; 
                   // 1 for moving the disk n from source to target rods
                   //   and moving n-1 disks from auxiliary to target rods
                   // 2 for backtracking to the previous call record
        
        // 建構子
        public HanoiCallRecord(int num, char source, char auxiliary, char target)
        {
            this.num = num;
            this.source = source;
            this.auxiliary = auxiliary;
            this.target = target;
            this.stage = 0;  // 預設從階段0開始
        }
        
        // 列印呼叫記錄
        public String toString()
        {
            return String.format("(n:%d,s:%c,a:%c,t:%c,s:%d)",
                    num, source, auxiliary, target, stage);
        }
    }
    
    // 模擬呼叫堆疊,解河內塔,將n個盤子從柱sourc,搬到柱target,透過柱auxiliary
    public static void hanoiUsingStacks(int num, char src, char aux, char tgt) 
    {
        Stack stack = new Stack<>();
        
        HanoiCallRecord initial = new HanoiCallRecord(num, src, aux, tgt);
        stack.push(initial);  // 壓入第1層呼叫記錄

        while (stack.isEmpty()==false) 
        {
            if(printStack) System.out.print("\n" + stack);
            
            HanoiCallRecord current = stack.peek();  // 檢視本層呼叫記錄
            int n = current.num;
            char source = current.source;
            char auxiliary = current.auxiliary;
            char target = current.target;
            int stage = current.stage;
            
           if (n == 1) // 執行特別任務,然後退回上一層任務
           {
                if(printOperation) 
                    System.out.print(String.format("\t\t%d: Move disk 1 from %c to %c", ++count, source, target));

                transfer(source, target);
                stack.pop();  // 彈出本層呼叫記錄,
            } 
            else if(stage == 0) // 階段0, 執行本層第0階段任務
            {
                // solveHanoi(n - 1, source, target, auxiliary);
                HanoiCallRecord next = new HanoiCallRecord(n - 1, source, target, auxiliary);
                stack.push(next); // 壓入下層呼叫記錄
                current.stage++;  // 更新本層呼叫記錄的階段欄位
            }
            else if(stage == 1) // 階段1, 執行本層第1階段任務
            {
                printStacks(nDisks - n);            
                if(printOperation)
                    System.out.print(String.format("\t\t%d: Move disk %d from %c to %c", ++count, n, source, target));
                transfer(source, target);
                printStacks(nDisks - n);

                // solveHanoi(n - 1, auxiliary, source, target);
                HanoiCallRecord next = new HanoiCallRecord(n - 1, auxiliary, source, target);
                stack.push(next);  // 壓入下層呼叫記錄
                current.stage++; // 更新本層呼叫記錄的階段欄位
            }
            else if(current.stage == 2) // 階段2,本層任務完成,退回上一層任務
            {
                stack.pop();  // 彈出本層呼叫記錄,
            }
        }
    } 

    // 測試主程式
    public static void main(String[] args) 
    {
        nDisks = 3; // Number of disks
        count = 0;
        for(int i=nDisks; i >= 1; i--) stackA.push(i);
        
        System.out.print("Hanoi Tower by Implicit Call Stack 遞迴版");

        printStacks(0);
        solveHanoi(nDisks, 'A', 'B', 'C');
        printStacks(0);
        
        // ===================================
    
        count = 0;
        stackA.clear();
        stackB.clear();
        stackC.clear();
        for(int i=nDisks; i >= 1; i--) stackA.push(i);
                    
        System.out.print("\n\nHanoi Tower by Explicit Stack 模擬呼叫堆疊版");
        
        printStacks(0);
        hanoiUsingStacks(nDisks, 'A', 'B', 'C');
        printStacks(0);
    }
}    

how to categorize the various VPN technologies?

虛擬私有網路(VPN,Virtual Private Network) 技術可在公有網路上傳送加密封包,讓外部主機猶如處於公司內部網路。VPN依管理者是誰分為企業VPN及服務供應商VPN。企業VPN依據使用情境分成站點對站點類及遠端存取類VPN。

站點對站點類VPN使用技術包含IPsec VPN,GRE over IPsec,思科DMVPN,IPsec VTI。遠端存取類VPN使用技術包含客戶端IPsec VPN連線,無客戶端SSL連線。其中,GRE為通用路由封裝(Generic Routing Encapsulation),DMVPN為動態多點虛擬私有網路(Dynamic Multipoint Virtual Private Network),VTI為虛擬隧道介面(Virtual Tunnel Interface)。

服務供應商VPN包含新式 第2層 或 第3層 MPLS VPN,及傳統 訊框中繼 或 ATM VPN。其中,MPLS 為多重協定標籤交換(MultiProtocol Label Switching),ATM 為非同步傳輸模式 (Asynchronous Transfer Mode)。

IPsec (Internet Protocol security) 屬於待評提案 (Recommendation For Comments, RFC) 之標準,定義了 VPN 如何認證和保護 IP 封包的安全。IPsec 可以保護從第 4 層到第 7 層的流量。IPsec 提供重要安全功能,包含使用加密技術保證外人看不懂,達到機密性;使用雜湊技術保證不遭篡改,達到完整性;使用 Diffie-Hellman 系列的網際網路金鑰交換 (Internet Key Exchange, IKE) 協定,以預先共用金鑰(密碼),數位憑證,或 RSA 憑證進行驗證,達到來源及去處之防偽。

IPsec 透過封裝安全協定 (Encapsulation Security Protocol, ESP) 支援傳輸模式 (Transport Mode) VPN,供端點對端點 (end-to-end) 主機之間加密傳輸;以及隧道模式 (Tunnel Mode) VPN,供站點對站點 (site-to-site) 網段之間加密傳輸。

以上總結可將VPN技術分類如下:

  • A.企業自架VPN
    • 1.遠方存取VPN (即端點對端點VPN): 
      •  無客戶端 SSL/TLS VPN (第4層)
      •  客戶端 IPsec傳輸模式VPN (第3層)
    • 2.站點對站點VPN
      •  IPsec隧道模式VPN (第3層)
      • GRE over IPsec
      • 思科DMVPN
      • IPsec VTI
  • B.供應商維護VPN
    • 1.傳統:訊框中繼 或 ATM VPN
    • 2.新式:MPLS VPN

 參考: CCNA3: 08 VPN and IPsec Concepts

why so design the same origin policy and cors?

為了確保網頁不去攻擊別人,瀏覽器一般會實作同源政策(Same Origin Policy, SOP),限定網頁內嵌讀取,或腳本連線存取的對象,必須是相同網站的其他資源,例如圖片,影音,API服務等。

但是很多情況,網頁須要跨域存取資源,遂有伺服端提供跨源資源分享(Cross-Origin Resource Sharing, CORS)的設計。其原理是瀏覽器向伺服器提出請出時,送出來源(Origin)標頭,由伺服器依據組態,回應存取控制允許來源(Access-Control-Allow-Origin) 標頭,供瀏覽器決定是否存取資源。若請求無來源標頭,或來源不在組態設定的來源清單中,則不回應存取控制允許來源標頭

這種跨源分享的防弊設計建立在瀏覽器及伺服器雙方合作的基礎之上。瀏覽器須能自我克制,參考伺服器意見,才決定是否取用資源。因為如果使用wget或curl等客戶端命令列工具,其實也可忽視伺服器意見,直接取用資源。

又CORS機制的設計為何不是網頁宣告我可以取用誰,而是設計成網頁宣告誰可以取用我。其理由在若採取前者,網頁宣告我可以取用誰,則駭客只要攻入一個網站,就可以輕易偽造此宣告,達成跨域存取任意資源的後果。而現實採取後者,網頁宣告誰可以取用我,其理由在駭客須一一攻入資源提供方,顯然不符成本。

因此CORS機制,採用由伺服器回應瀏覽器,你是否在我的來源許可清單中的無老虎牙設計,顯然其防弊精神不在避免伺服器受攻擊,而是在瀏覽器主動SOP配合下,避免網頁成為攻擊工具,又能合理取用受控資源。

Reference: 1.Medium: 簡單弄懂同源政策 (Same Origin Policy) 與跨網域 (CORS)

apps for monitoring CPU and GPU temperatures and other resources on Linux

想隨時用手機 App 透過 ssh 連線監視 Linux 機器的資源使用及硬體溫度可考慮如下作法。

(1)  set up a monitor account on Linux 建立監視用帳號

$sudo adduser  --home=/home/user_name  user_name

$grep user_name /etc/passwd

$sudo edquota -p  source_user   user_name

$sudo quota -u user_name

(2) set up .ssh store in the monitor account 建立帳號公鑰存放目錄

mkdir -p ~/.ssh && chmod 700 ~/.ssh 

cat >> ~/.ssh/authorized_keys

chmod 600 ~/.ssh/authorized_keys

(3a) set up DaRemote App for Android 設定Android App

            Configure Name, Host, User, Key/Password 設定主機

    Monitor CPU/Memory/Disk/Network including CPU temperature 監視資源

    Use Shell Terminal 使用終端機

(3b) set up ServerCat App for iOS 設定 iOS App

ServerCat

  Status: Temperature 監視主機資源

Monitor CPU/Load Memory/Swap Upload/Download Read/Write

including core usage, threads, memory,
                  GPU memory, CPU/GPU temperature, disk usage

  Configure Host/+/ 設定受監視主機

Name,  Host,  Port,  User,  Password, SSH Key

  Execute/Select host 執行上傳公鑰指令

        Copy the Shell Command from KeyChain Store to 

                    Send the Public Key to the remote host

                    cmd: echo 'ssh-ed25519 xxxxxxxxxxxx ' >> !/.ssh/authorized_keys

Execute 

  Mange KeyChain/+/ 管理登入金鑰

        Configure a new SSH Authentication Key Pair 建立登入金鑰

                    Generate 2048 bit RSA Key, or

    Generate ED25519 Key (Recommended)

Copy SSH Authentication Key to Server 產生上傳公鑰指令

  echo 'ssh-ed25519 xxxxxxxxxxxx ' >> !/.ssh/authorized_keys


how to sort a pandas dataframe by two keys?

# 對於pandas資料框df如果須要依據主鍵文字欄位sentiment,

# 次鍵文字欄位text的長度進行紀錄排序,可參考如下寫法。 

def sort_by_two_columns(x): # x 表示某列資料的排序欄位值

    if x.name == 'sentiment': # 若詢問排序欄位為sentiment,回傳欄位值供排序
        return x
    elif x.name == 'text': # 若詢問排序欄位為text,回傳欄位長度值供排序
        return x.str.len()

# 先依據主鍵文字欄位sentiment由小到大,
# 再依據次鍵文字欄位text的長度由小到大,
# 排序結果重新回傳一個新資料框

sort_df = df.sort_values(by=['sentiment', 'text'], 
key=sort_by_two_columns, ascending=[True, True], inplace=False)

pd.set_option('min_rows', 100) # 資料框至少顯示100列

sorted_df = sort_df.drop_duplicates() # 去除重複記錄

how to install Ubuntu as subsystem of Windows with a ssh server?

 傳統一台 Windows 主機若要同時跑 Linux 作業系統,不是要安裝 Cygwin 套件,就是要透過 VirtualBox 等虛擬機軟體安裝 Linux。現在 Windows 的 WSL (Windows Subsystem for Linux) 技術逐漸成熟,可以在 Windows 環境中,啟用 Linux 子系統,方便雙方資料共享,及執行 Linux 程式和指令。以下簡短摘要步驟,說明如何透過 Microsoft Store 微軟商店,安裝 Ubuntu 22.04.1 LTS 作業系統。

1.啟動 Windows 的 Linux 子系統 (WSL) 功能

控制台/程式集/程式和功能: 開啟或關閉 Windows 功能

勾選: Windows 子系統 Linux

2.安裝 Ubuntu 作業系統

Microsoft Store: 找尋安裝 Ubuntu 22.04.1 LTS,建立帳戶myuser

3.啟動 Ubuntu 作業系統終端機

建立桌面捷徑圖示:

目標: C:\Windows\System32\wsl.exe

開始位置: \\wsl$\Ubuntu-22.04\home\myuser

或使用 SearchBox: ubuntu2204

4.安裝 ssh 終端機登入服務,供遠方登入本機之用

4.1.安裝 ssh 服務

              WSL終端機執行如下指令:

> sudo apt remove openssh-server

> sudo apt install openssh-server

> sudo service ssh start

4.2.設定 ssh 服務於 Windows 開機時自動啟動

4.2.1. 設定權限,允許不輸入密碼即可啟動服務

                 WSL終端機執行如下指令

      > sudo vim /etc/sudoers

%sudo ALL=NOPASSWD: /usr/sbin/service ssh start

4.2.2. Windows 工作排程器設定如下開機任務

設定工作排程器 (Task Scheduler),開機時自動啟動

Basic Task

Trigger: When the computer starts

Program: C:\Windows\System32\wsl.exe

Argument: sudo /usr/sbin/service ssh start

               參考: https://www.howtogeek.com/746532/how-to-launch-cron-automatically-in-wsl-on-windows-10-and-11/

4.3.設定金鑰目錄權限,拷貝遠方客戶的公鑰進來,供客戶登入本機時簽發訊息核對身份之用

              WSL終端機執行如下指令

> mkdir ~/.ssh            # 家目錄下建立金鑰目錄

> chmod 700 ~/.ssh # chmod 指令只對/根目錄 (wslfs) 有效,對/mnt/c (drvfs)掛載目錄無效

> scp -p user@host:.ssh/*pub .    # 拷貝遠方既有.pub公鑰到本機個人金鑰目錄,供身份核對之用


註: 
1. 若想要知道或切換目前 WSL 版本,可使用如下指令。
> wsl -l
Windows 子系統 Linux 版發佈:
Ubuntu-22.04 (預設值)

> wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-22.04    Running         1

> wsl --set-default-version 2

2. 不從微軟商店,直接從CMD命令列也可查詢及安裝Linux,指令如下:
> wsl --list --online
以下是可安裝之有效發佈的清單。
使用 'wsl --install -d <Distro>' 安裝。

NAME                                   FRIENDLY NAME
Ubuntu                                 Ubuntu
Debian                                 Debian GNU/Linux
kali-linux                             Kali Linux Rolling
Ubuntu-18.04                           Ubuntu 18.04 LTS
Ubuntu-20.04                           Ubuntu 20.04 LTS
Ubuntu-22.04                           Ubuntu 22.04 LTS
OracleLinux_7_9                        Oracle Linux 7.9
OracleLinux_8_7                        Oracle Linux 8.7
OracleLinux_9_1                        Oracle Linux 9.1
openSUSE-Leap-15.5                     openSUSE Leap 15.5
SUSE-Linux-Enterprise-Server-15-SP4    SUSE Linux Enterprise Server 15 SP4
SUSE-Linux-Enterprise-15-SP5           SUSE Linux Enterprise 15 SP5
openSUSE-Tumbleweed                    openSUSE Tumbleweed

Use of Weka for sentiment analysis in traditional Chinese

網路上有關 Weka機器學習 軟體的文字分類範例大部份都是針對英文,以下示範針對繁體中文的作法。

由於繁體中文的標記語料很少,本範例將取自 SnowNLP 釋放的簡體中文標記語料。 SnowNLP 正負情感資料集 共計34,880筆(35k)日常聊天語料,包括負面情感(neg.txt) 18,576筆(19k),正面情感(pos.txt) 16,304筆(16k)。前處理利用 OpenCC 軟體轉換為繁體,再利用 jieba 軟體空格斷詞,存成.csv檔,其中3欄位為原始文字 text, 空格斷詞文字 token_text, 情感判定 sentiment,0表示負面,1表示正面。

用Weka分類軟體讀入.csv檔,利用StringToWordVector過濾器將 token_text 欄位由String型別轉為眾多nominal欄位,以sentiment欄位為預測目標,進行1次性訓練及測試。測試選項: Percent 66% 當訓練集(23k),34%當測集(12k)。

所有分類器都使用預設參數,準確率accuracy,訓練時間training time,測試時間testing time的結果如下,可發覺準確率表現最好為RandomForest分類器。

SnowNLP classifiers accuracy training time (s) testing time (s)
weka.classifiers.rules      
  ZeroR 52.80                  0.03             0.44
  OneR 62.10                12.23             0.38
         
weka.classifiers.trees      
  J48 85.00           2,694.75             0.37
  RandomForest 93.64              459.36             8.94
         
weka.classifiers.bayes      
  NavieBayesSimple 8.14                  5.43             7.35
  NaiveBayesMultinominalText 52.80                  0.14             0.28
  NaiveBayes 70.60                14.10             9.77
  NaiveBayesMultinominal 78.50                  0.14             0.94
         
weka.classifiers.functions      
  MLP 52.80       405,797.00           83.62
  SimpleLogistic 81.90           1,101.32             1.39
  Logistic 83.00              294.00             0.86
  SMO 83.20           5,231.83             1.94
         
weka.classifiers.lazy      
  IB1 86.20                  1.80    23,146.80
  IBk 86.70                  0.04           99.95
 

Disable UDP to solve frequent RDP disconnection

解決 RDP 遠端桌面經常斷線問題:「關閉 UDP 傳輸」 在使用 Windows 內建的 遠端桌面(RDP, Remote Desktop Protocol) 連線時,你是否也常遇到連線突然卡死、畫面凍結,或是頻繁跳出「連線已中...

總網頁瀏覽量