剛好看到以前的老師在分享這篇,雖然已經很久沒碰資料科學了,趁這個機會簡單翻譯而且複習一下,下面的翻譯跟舉例不一定完全正確,有誤的地方再請諸位大神幫忙指正。

Image for post
Image for post
Ref:geckoboard
  1. Cherry picking 單方論證

只說自己想要說的。舉例來說就是採櫻桃的工人只採好的櫻桃,會讓你覺得所有的櫻桃都是好的。或只說單一支持/反對的論點,忽略其他不提,這讓我想到公視對「帶風向」這詞的定義也是如此。

2. Data dredging 資料捕撈/資料挖泥

一般研究都是先提出假說,再透過實驗設計、執行與最後的數據來證實或推翻假說,而 Data dredging 指的是順序顛倒,有了資料後再去看這資料有甚麼表現比較好的特性去選擇研究主題。

例如一開始想研究翹課頻率跟成績的關聯,但後來發現沒關係,可是跟抽菸有關,於是就把題目直接改成翹課與抽菸的關聯。

不得不說這種情況在研究所應該還蠻常見的XD

3. Survivor bias 生存者偏差

這個大家都應該聽過二戰戰鬥機的例子,軍方在討論如何改善戰機的存活率時,若只觀察成功返回的飛機彈孔位置就認為這些地方比較常中彈是不對的,因為這些彈孔代表的其實是中彈還是可以飛行的位置。

至於中彈後會導致直接損毀的位置是觀察不到的(因為都墜毀了)。

4. Cobra effect 眼鏡蛇效應
針對問題的解決方案,反而是該問題惡化。這個詞的來源是英國政府為了減少當初殖民印度時的眼鏡蛇數目,就公布一項規定:殺蛇可換到不少錢,於是就開始興起養眼鏡蛇換賞金的風潮,隨後英國政府也意識到這件事情便把賞金取消。

取消之後呢?那些養眼鏡蛇的馬上都把所有的眼鏡蛇給放生了,於是野外的眼鏡蛇又更多了XDD

5. False causality 因果謬誤

觀察到 A 事件發生在 B 事件之後,或是 A、B事件有相關性,就認為A、B事件互為因果, 之前聽過的例子是友人調查巧克力食用量與健康的關係,發現世界上巧克力食用量越高的地區,健康情形也越好。但這代表巧克力對健康有益嗎?不,因為巧克力食用越多,通常代表該區域的經濟狀況也較好。

6. Gerrymandering 傑利蠑螈

來自於美國曾經發生的事件,透過選區劃分可以增加/減少特定政黨的形式,導致為了操控席次而進行各種怪異的選區畫分法,結果就是有一個選區的形狀特別奇怪像蠑螈而得名。

在資料科學裡就是改變資料的分組方式藉此操縱最後的結果。

7. Sampling bias 取樣誤差

一開始在抽樣的人群便無法代表母體,比如說你在台北市大安區街頭抽樣每個人的薪水,就拿這些人的薪水代表全台灣的人,從無法代表母體分布的樣本中抽樣會導致的誤差。

8. Hawthorne effect 霍桑效應

在霍桑工廠進行的實驗,當初的實驗想要知道那些變因會影響員工的生產力,但意外發現觀察者知道自己被觀察時就會改變行為傾向。當長官給予下屬關懷或照顧時,員工的生產力提升也可以用霍桑效應解釋。

9. Gambler’s fallacy 賭徒謬誤

想像一個在賭場賭骰子的狀況,如果連續出現了很多次 6,就認為下一次一定會/不會再是 6,或是認為某個點數很久沒出現所以下次一定會出現的想法。因為就機率來看公正骰子出現的點數機率都是 1/6。

10. Regression toward the mean 回歸均值

單一一次的表現都會不可避免地受到隨機誤差影響,可能增加也可能降低,但如果次數一大,原本的差異就會回歸到平均而被弭平,比方說我發現某個方法在第一輪時預測狀況特別好,但多做幾個 Epoch 後,這個方法的優勢就會被弭平。

另一個例子就是股價短期會收到隨機波動的影像,所以兩個公司表現差不多的時候,股價短期內卻有可能呈現一個上漲、一個下跌,但只要觀察時間長,這兩隻公司的股價最終還是會回到均值。

11. Simpson’s paradox 辛普森悖論

如果我們有兩種資料:A、B,兩種評分方式:甲、乙,不管在甲乙這兩種評分方式下都是 A 勝出,但不代表最終結果 A 一定會勝出。每個評估下都強的資料,在綜合評估的時候不一定會強。

舉一個維基百科上的例子:

法學院的學生組成&錄取率:


這幾個月因為授課的關係又把 Introduction to Algorithms 這本演算法大學教科書讀過,想想真慚愧以前修課讀書都沒有那麼認真XDDD

但因為這本書有將近 1400 頁,而資料結構、演算法普遍都是一學期 3 學分的課程,整學期通常有20~25學分,對一般學生而言是不可能在一學期內讀完的。

Image for post
Image for post

讀完一部分之後,才體會到「經典之所以是經典,在於每次閱讀都能夠有不同的體悟」,比方來說,我之前有嘗試寫過虛擬貨幣的搬磚,雖然後來失敗了(詳:https://bit.ly/3bb52Ge),但那時候並沒有體認或使用到演算法,單純使用暴力解,直到看到書上的例題,才發現其實搬磚問題是可以用演算法中的最短路徑、檢查負環來解答的。


搬磚這個詞如果有在虛擬貨幣圈裡頭應該不難聽到,通常會想到的都是交易所間的搬磚。因為各交易所間的價格不一,導致中間有機會進行套利,比方說幣安的比特幣價格如果高於Bitifinex,便可以由Bitifinex購入比特幣後再到幣安轉賣,反之亦然。

Image for post
Image for post

這種方式其實跟傳統低買高賣的貿易方式很像,差別就在搬磚通常全部都由電腦即時達成,而且這種搬磚方式通常有低風險的特性,不管如何經過一輪手上的幣都會變多,需要承擔的風險就是當幣值下跌的時候手上的幣可能變得一文不值,另外也有可能因為延遲搶不到其中一邊的的單而導致虧損。

值得一提的是,通常因為交易所間的匯款會收取高昂的手續費,也會耗去不少時間,因此如果要進行交易所間的搬磚套利,會同時在兩交易所中事先儲值好要搬得幣種,以利在匯差產生時便即時下單交易。例如如果要在幣安與 Bitifinex 間進行比特幣與 USDT 的搬磚,則必須要在兩交易所內事先儲值好 USDT 與 BTC,當幣安價格高於 Bitifinex 時,立刻賣出幣安裡的BTC,並同時賣出Bitifinex內的USDT。

但這裡要介紹的是另外一種搬磚方式─交易所之內的搬磚,我們以幣安交易所為例,幣安交易所上面有四種交易對:BNB/BTC/ETH/USDT,如果交易對間產生價差,便可以透過中間價差來賺取微薄的利潤。

但實際上還需要扣去交易所交易的手續費,以剛剛提的幣安交易所為例,它的手續費約0.1%,以BNB付款的手續費約0.075%,再以註冊推薦碼反傭20%計算後大約0.06%。(持有500BNB可以反傭40%)。


Image for post
Image for post

節點間的同步與廣播

我們現在已經能夠讓使用者端與節點端彼此溝通,而且能夠讓使用者在不需要儲存所有交易明細的狀況下向節點查詢餘額或是發起交易,但我們的節點也只有一個,在這個狀況下其實運作方式跟傳統中心化的方式並無差異。

因此現在的目的是要讓外界的人可以自由加入節點的運作與挖掘新區塊,在這過程中也牽涉到區塊或交易的廣播(必須把收到的新資訊廣播給彼此,區塊鏈裡的資料才會一致),這一步完成後我們的簡易區塊鏈也就大功告成了!

同步區塊

為了與已經上線運作的區塊鏈同步,需要向已知的節點發起請求,要求節點將目前所有的資料都傳遞過來。因為我們選用的是Stream Socket,接收到的資料是連續的,為了避免資料流斷開因此直到讀到len(response) % 4096不為零才停止。(但其實會有Bug,但因為機率很小只有1/4096這裡先忽略)。接收到資料後就把目前鏈上的資料同步。

接受並判別訊息

接收資訊的部分需要對其餘節點傳來的資訊做對應的處置,有下面四種:

  1. 接收到同步區塊的請求:把目前的區塊鏈上的資料都dump一份給對方
  2. 接收到挖掘出的新區塊:確認是否有符合Hash的規則,有的話就把它加入鏈上,改挖掘下一區塊
  3. 接收到廣播的交易:把交易置入等待中的交易pending_transactions
  4. 接收到新增節點的請求:把位置加到之後要廣播的清單中

接收並驗證廣播的區塊

一旦接收到新區塊,必須對區塊的內容與哈希加以驗證,確認資料格式是正確的同時也要把裏頭被打包好的交易從等待中的交易pending_transactions移除,否則該筆交易就會被執行兩次!

如果廣播的區塊驗證通過,改挖掘下一塊

如果通過上一步的驗證,則本地端的挖掘工作必須暫停,直接挖掘下一個新區塊。在這裡我們也修改nonce的產生方式,不再是統一由1開始逐漸+1,否則永遠都會是算力最高的節點會挖到。

挖掘到新區塊,廣播給其他節點

如果是自身挖到新區塊的話,就要把這個新區塊廣播給其他節點囉!

執行我們的區塊鏈與雙節點

首先我們運行第一個節點,並指明它的port為1111

python .\Blockchain.py 1111

接著可以運行第二個節點,並指明它的port為1112、請它去連接與同步127.0.0.1:1111。

python .\Blockchain.py 1112 127.0.0.1:1111

接著就可以看到兩邊不停地交換挖掘到的新區塊了!


Image for post
Image for post

我們的區塊鏈還少了一個必要的東西:P2P網路,區塊鏈沒辦法接收其他人的請求,只能在本機端跑,因此接下來就會來透過通訊把區塊鏈區分成:節點端(礦工端)與客戶端!

節點與使用者的溝通

前置作業

現在的目標是模擬節點或礦工端跟使用者端的互動,節點儲存了自創世塊以來的所有交易明細,同時也負責接受交易、打包交易至區塊、挖掘區塊、廣播挖掘到的區塊等等;而使用者端通常只會讀取鏈上的資料與發起交易,也因為交易紀錄動輒數十GB起跳,為了效率與經濟的考量,使用者端通常也不會儲存交易紀錄。

為了方便模擬我們把兩端的程式都跑在同一台電腦上,這裡選用的通訊方式是socket;也因為加入通訊後程式必須同時處理多樣的工作,所以使用thread來讓程式能夠順利執行監聽與挖礦這兩件事情。

節點的功能

節點的功能與我們之前所撰寫的並無差異,也就是需要:

  1. 產生公私鑰(錢包地址)
  2. 儲存交易紀錄
  3. 確認帳戶餘額
  4. 驗證交易上面的數位簽章
  5. 打包交易並挖掘新區塊

使用者端的功能

使用者端至少需要能夠產生公私鑰簽署交易,簡單說就是為了避免私鑰外洩的風險,所有跟私鑰有關的作業(產生公私鑰或簽署數位簽章)通通都由使用者端完成,不需要仰賴外界或是將私鑰傳至節點即可完成。

  1. 產生公私鑰(錢包地址)
  2. 向節點查詢資料
  3. 發起並簽署交易

節點端

在節點端這裡首先我們需要準備socket的端口讓外界可以連入,因為測試時節點端與使用者端都在本機上,所以IP地址給的是本機的127.0.0.1,至於Port則因為每一個節點所用的Port不同,因此在執行程式時再透過命令列的參數給定。

準備socket連線的端口

開thread監聽新連線與傳入訊息

為了在打包交易與挖礦的同時能夠接收外界的資訊,我們開一個thread在bind之後等待外界的新連線s.accept(),同時在每次新連線建立之後,又為每一個獨立的連線開一個thread去接收並且處理資訊。

接收訊息後處理

這裡我們根據使用者傳遞過來的資料,判別使用者想要做

  1. 取得帳戶餘額
  2. 發起交易

再根據使用者想做的事情分別去接收不同參數,並且回傳結果給使用者。

啟動節點

完成上面接收並且處理資訊的過程後,便可以啟動節點、打包新交易、挖掘新區塊、調節難度,同時我們也可以根據外界的請求做相對應的處置。在這裡為了測試轉帳,我們同時產出一組礦工的公私鑰來使用(轉帳的前提是帳戶裡必須有足夠的餘額,在一開始也只有礦工有,因此我們只能用礦工的公私鑰來發起交易)。

客戶端

客戶端這裡的工作相對單純,首先建立與節點間的socket聯繫,這裡節點的IP因為同在本地端因此也為127.0.0.1,節點端的Port的部分則在啟動程式碼時再帶入。之後就可以開一個Thread不停去接收socket傳過來的資訊。

接收訊息

產生錢包地址與公私鑰

為了避免私鑰外洩,強烈建議公私鑰都在使用者的本地端產生,在利用RSA加密法產生一對鑰匙後,再把裏頭的前綴與後綴字濾掉後便是我們的公私鑰。比方說公鑰是:

— — -BEGIN PUBLIC KEY — — -
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANrG/HiSL6M41EaDsmpVKW+E4QZKaiW2KZD2RR7If7f9jMZiojoS1/uM0N6AQ2G8TUkPHjBuAnS1Dn4PJZAUysMCAwEAAQ==
— — -END PUBLIC KEY — — -

產生的地址便是

MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANrG/HiSL6M41EaDsmpVKW+E4QZKaiW2KZD2RR7If7f9jMZiojoS1/uM0N6AQ2G8TUkPHjBuAnS1Dn4PJZAUysMCAwEAAQ==

私鑰原本是:

 — — -BEGIN RSA PRIVATE KEY — — -
MIIBOwIBAAJBANrG/HiSL6M41EaDsmpVKW+E4QZKaiW2KZD2RR7If7f9jMZiojoS1/uM0N6AQ2G8TUkPHjBuAnS1Dn4PJZAUysMCAwEAAQJBAKWsPHKd2X9UQMQpZQnK9fbifHmEDsACI5YIOK2oDbfo3mzW+gfxHtS1YVZz5TlymUAwm+qxBnwjTPEm+Jqn9ukCIQD1pl7vOofGdAiPBM0M2mJpOh7/b82XSCO/LCyRaP8pPwIhAOP+wxujrxReBwzZmH6rqpKuuK2ueEVY/eVxpnHfaZl9AiAlT2mn6DnrGICcSFxkkV7VILDIl1Cgo6JaTPlP9KScvQIhAIMFft49XHnZ5zdNPMNep7GP0vWMk/VWROI8Q6ig+TCJAiBFug2F+uZz3Gma5ySWBN49eH95o1PqYkDcoATkZ90skQ==
— — -END RSA PRIVATE KEY — — -

過濾後產生的私鑰便是:

MIIBOwIBAAJBANrG/HiSL6M41EaDsmpVKW+E4QZKaiW2KZD2RR7If7f9jMZiojoS1/uM0N6AQ2G8TUkPHjBuAnS1Dn4PJZAUysMCAwEAAQJBAKWsPHKd2X9UQMQpZQnK9fbifHmEDsACI5YIOK2oDbfo3mzW+gfxHtS1YVZz5TlymUAwm+qxBnwjTPEm+Jqn9ukCIQD1pl7vOofGdAiPBM0M2mJpOh7/b82XSCO/LCyRaP8pPwIhAOP+wxujrxReBwzZmH6rqpKuuK2ueEVY/eVxpnHfaZl9AiAlT2mn6DnrGICcSFxkkV7VILDIl1Cgo6JaTPlP9KScvQIhAIMFft49XHnZ5zdNPMNep7GP0vWMk/VWROI8Q6ig+TCJAiBFug2F+uZz3Gma5ySWBN49eH95o1PqYkDcoATkZ90skQ==

同時這裡的程式碼節點端也會用到喔!


Image for post
Image for post

現在遇到一個問題:

如果未經驗證就把交易紀錄送上鏈,那任意人都可以隨意移轉他人帳戶的餘額

很明顯這樣做是有問題的。因此接下來我們要處理的便是利用非對稱加密驗證發起交易者的身分與權限,其中又可以分成以下三個步驟:

  1. 利用非對稱加密中的RSA加密產生公、私鑰與地址
  2. 利用產生的公私鑰簽章後發送交易
  3. 試著跑起整個鏈並發起交易

非對稱式加密

區塊鏈只存在網路上,我們很明顯地無法透過身分證等文件去確認發起者的身分,因此這裡用到的是非對稱加密,這裡先簡短說明一下非對稱加密的功能:非對稱加密會得到兩把鑰匙:公鑰與私鑰,功能很簡單就一句話

可以公鑰加密私鑰解密,也可以私鑰加密公鑰解密。

也就是每個人在產生地址的時候同時會得到一把公鑰、一把私鑰,通常公鑰會釋出給對方,私鑰會自己持有以證明自己是該公鑰的持有者。


Image for post
Image for post

前言

這幾周虛擬貨幣狂漲,短短半年從最低點到現在已經漲了約莫十倍,從2017的牛市接觸到現在往若有種時光倒流的感覺,彷彿從前那段睡一覺起來就可以漲10%的日子又來了一次。


Image for post
Image for post

平常看的 Full HD 像素是 1920x1080,代表橫的方向有 1920 個畫素、直的有 1080 個畫素,但因為光有三原色,為了顯示顏色,每個畫素又必須分成 RGB 三個維度,也就是一張彩色圖片可以看做是一個三維陣列 (1920x1080x3)。

但事實上可見光是電磁波連續光譜中的一段,光在物理學裡頭是沒有三原色的。

之所以光會有三原色,是因為我們眼中感應可見光的視錐細胞分成三種:L、M、S,這三種細胞大致對應到紅、綠、藍。也就是我們用這三種感光細胞去「感受」這個世界,對於大腦而言所有的顏色都是由 L、M、S 三種感光細胞的刺激加種而成,於是光才有了三原色。


經營粉專至今三個月左右,扣掉中間比較忙幾近停更的一個月,前後大約花了兩個月在上頭,也是實際開始經營後才慢慢理解到為什麼社群平台上的生態會如此。

臉書或水管的演算法是這樣的:首先他們會把你的內容推播給一小部份的人,如果受眾對這篇文反應好(按讚或留言),則平台就會把這個內容推播給更多的人,這在平常狀況下可以過濾掉那些沒營養、大家不想看的廣告文。

但也因此在這種演算法下最重要的是踴躍互動的鐵粉,就像是前幾天出征AIT或事實查核中心的那群人,雖然我覺得這種想法或行為非常不妥,但日常他們就是最頻繁用按讚或留言來表達意見,也就是說,平時就是由他們決定臉書上在流傳甚麼。

我也不諱言我不喜歡那些專帶風向與仇恨的匿名粉專,但面對現實,他們的互動率、觸及率就是高得嚇人,越是斷章取義、寫得越激動、最好還搭配一張簡單的圖,按讚數輕易就可以到粉專人數的1/10以上,這在任一個知識或討論性質的粉專上頭都很難看到。

而且他們花的時間可能還只有你的1/10,以我為例每篇文會花6~8小時不等,其他像是科技島讀、寫點科普或是影音類的超級歪、囧星人等只會比我更高。但如果改用這種淺碟的方式經營只要花1/10的時間,卻可以有10倍以上的觸及互動率,看到這種現象不心動也難。

你可能會想那不要每天發文就好啦?但如果發文頻率太低,臉書或水管會直接調降你下次發文的觸及率,所以我目前都維持著一到兩天廢文、一天認真文的頻率在發,而且其中一半的認真文都是修改自以前寫過的東西,沒辦法我跟大多數人一樣平常還得工作賺錢生活。(所以請原諒我有時候Po的廢文QQ)

資訊的產出是有價的,而且要價不斐。平常看到的那些文章並非免費,通常是由背後的廣告商或是政黨金主買單,在這種現實下,有能力產出優質內容的作者最後會慢慢退出社群平台,轉向菁英訂閱制的媒體,而臉書最後就變成一個導流的渠道。

我有在追的王伯達、科技島讀、區塊勢都是如此,這些人都被趕到訂閱制媒體了,他們註定無法在臉書的演算法下存活下來。


Image for post
Image for post

在安裝程式時,常會看到 dll 這種副檔名的出現,但 dll 是甚麼?它是幹嘛用的?

DLL 的全名是動態連結函式庫 Dynamic-link library ,Microsoft給的解釋是:

DLL 是一種包含可供多個程式同時使用的程式碼和資料的文件庫,當多個程式使用相同的函式程式庫時,DLL 可以減少磁片上和實體記憶體中載入的程式碼的重複。

(引文自:https://bit.ly/36ae3v5 原本內文感謝網友范姜士武指正)

因為 Python 目前是使用者最多的語言,因此接下來用 Python 引入用 C 寫的 dll 為例,看 dll 檔是怎麼幫助我們擷取各種程式語言的長處。

測試時用的程式碼是利用遞迴算斐波那契數列,我們也可以同時測試 Python 與 C 在執行速度上的差異。

About

李耕銘

一個普通的肥宅QQ

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store