貝斯女王島走出油污陰霾 褐鵜鶘庇護區揭牌

摘錄自2020年3月3日公視報導

美國路易斯安那州的貝斯女王島,是褐鵜鶘主要的棲地,過去因為遭到漏油事件重創,環境危害嚴重。不過在肇事的英國石油公司賠償下,將擴建庇護區。

路易斯安那州官員為重建的水鳥庇護區揭牌同時表示,過去人類對牠們棲地所造成的傷害長達10年,現在要還給牠們更乾淨、更安全的家。各界也希望今年夏天,貝斯女王島能跟往年一樣有約6500隻褐鵜鶘,以及約3000隻較小的水鳥遷徙到這裡築巢。

2010年墨西哥灣漏油事件,造成11人死亡,87天內超過1億加侖的原油洩漏。當時貝斯女王島72公里海岸線布滿油汙,褐鵜鶘全身浸泡在黑色汙泥的景象極為駭人,島上許多植物被遭毀,造成的生態浩劫引發全球擔憂。肇事的英國石油公司賠償200億美元,其中部分金額用來擴建養護1700公頃的海岸跟小島,今年還將投入8億美元持續重建工程。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

專家針對武漢肺炎警告 都市人長期處於空污下 恐增加感染死亡風險

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

Dell 將於 2040 年全面轉用再生能源

摘錄自2019年11月13日unwire HK報導

隨著更多的企業響應環保,作為知名的電腦公司 DELL 在近日亦宣佈了新的可持續發展計劃,指公司所有設施的 75% 電力將會使用可再生能源,直至 2040 年時將預計可獲 100% 的電力,並同時在計劃在過程中提高公司在生產及供應鏈上的能源效益,以達致低排放的目標為環保出一分力。

DELL 在早前宣佈公司將進行「Progress Made Real」的計劃,計劃內容主要包括在消費者購買的每一項設備時會回收同一污染水平的產品,以及在生產電力方面採用可再生能源。DELL 指出到 2030 年時公司一半以上的設備將會由回收材料或可再生物料而生產,在包裝上則會全面使用可重覆利用的物料。

不過 DELL 就並未透露公司是否會增加旗下所有裝置的使用壽命,但就指出對電子製造商而言,應對氣候變化的最佳方法是避免所有電子產品送往堆填區,而是重覆使用及物盡其用。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

不敵客訴壓力 澳洲超市延後對塑膠袋收費

摘錄自2018年8月3日蘋果日報澳洲報導

澳洲一間大型連鎖超市原本要實施塑膠袋需收費政策,希望可推動「減塑」為環保出一分力,不料顧客對此大感不滿,政策推出後已經第2次延長收費期限。

連鎖超市科爾斯(Coles)自上月1日起停用一次性塑膠袋,改向顧客提供可重複使用、質料更耐用的塑膠袋作過渡,直至本周三(1日)為止。超市原定顧客此後若索取塑膠袋,每個須收取15澳分(約3.4元台幣)。

然而科爾斯周三發聲明指,自禁用一次性塑膠袋後,有顧客反映需要更多過渡時間,以適應使用可重複使用塑膠袋,集團因此決定在昆士蘭、新南威爾斯、維多利亞及西澳洲等地繼續提供免費塑膠袋至8月29日,而南澳洲、塔斯馬尼亞等地區則仍繼續收費。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

遊客遽增破壞環境 紐西蘭國會報告示警

摘錄自2019年12月18日中央社威靈頓報導

紐西蘭國會今天(18日)提出報告警示,遽增的遊客數量正危害紐西蘭環境,也讓當地聞名遐邇、極具魅力的寧靜印象受到逐步破壞。

法新社報導,紐西蘭一向標榜「100%純淨」和「乾淨又環保」的形象,但近年來遊客數量遽增,許多人朝聖「魔戒」(The Lord of the Rings)電影拍攝地點大玩自拍,還有登山客、健行者及野生動物愛好人士。

紐西蘭國會環境事務專員厄普頓(Simon Upton)提出報告之際,紐國旅遊業正受到嚴格審查,因為白島(White Island)火山在9日爆發,造成16名外籍旅客和2名導遊喪命。

擁有490萬人口的紐西蘭每年吸引近400萬名外國遊客,厄普頓說,這項數據到了2050年可能增加2倍,厄普頓表示,基礎設施變得吃緊、環境承受壓力,紐西蘭原有的諸多品質正在消失,他說:「大批群眾正逐漸破壞許多外國遊客赴紐西蘭旅遊所尋覓的獨處感、寧靜和親近大自然的感覺,我們必須要問:我們是否正在殺雞取卵?」

厄普頓提到,紐西蘭人也是問題的一部分,在紐西蘭國定假期,著名景點湧現的國內遊客人潮比外國遊客還要多。

他還說,紐西蘭人已經習慣東加里羅步道(Tongariro Crossing)等著名景點「被遊客團團包圍」,而且問題只會持續惡化。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

阿裏面試官最喜歡問的21個HashMap面試題

1.HashMap 的數據結構?

A:哈希表結構(鏈表散列:數組+鏈表)實現,結合數組和鏈表的優點。當鏈表長度超過 8 時,鏈錶轉換為紅黑樹。

transient Node<K,V>\[\] table;

2.HashMap 的工作原理?

HashMap 底層是 hash 數組和單向鏈表實現,數組中的每個元素都是鏈表,由 Node 內部類(實現 Map.Entry接口)實現,HashMap 通過 put & get 方法存儲和獲取。

存儲對象時,將 K/V 鍵值傳給 put() 方法:

①、調用 hash(K) 方法計算 K 的 hash 值,然後結合數組長度,計算得數組下標;

②、調整數組大小(當容器中的元素個數大於 capacity * loadfactor 時,容器會進行擴容resize 為 2n);

③、i.如果 K 的 hash 值在 HashMap 中不存在,則執行插入,若存在,則發生碰撞;

ii.如果 K 的 hash 值在 HashMap 中存在,且它們兩者 equals 返回 true,則更新鍵值對;

iii. 如果 K 的 hash 值在 HashMap 中存在,且它們兩者 equals 返回 false,則插入鏈表的尾部(尾插法)或者紅黑樹中(樹的添加方式)。(JDK 1.7 之前使用頭插法、JDK 1.8 使用尾插法)(注意:當碰撞導致鏈表大於 TREEIFY_THRESHOLD = 8 時,就把鏈錶轉換成紅黑樹)

獲取對象時,將 K 傳給 get() 方法:①、調用 hash(K) 方法(計算 K 的 hash 值)從而獲取該鍵值所在鏈表的數組下標;②、順序遍歷鏈表,equals()方法查找相同 Node 鏈表中 K 值對應的 V 值。

hashCode 是定位的,存儲位置;equals是定性的,比較兩者是否相等。

3.當兩個對象的 hashCode 相同會發生什麼?

因為 hashCode 相同,不一定就是相等的(equals方法比較),所以兩個對象所在數組的下標相同,”碰撞”就此發生。又因為 HashMap 使用鏈表存儲對象,這個 Node 會存儲到鏈表中。

4.你知道 hash 的實現嗎?為什麼要這樣實現?

JDK 1.8 中,是通過 hashCode() 的高 16 位異或低 16 位實現的:(h = k.hashCode()) ^ (h >>> 16),主要是從速度,功效和質量來考慮的,減少系統的開銷,也不會造成因為高位沒有參与下標的計算,從而引起的碰撞。

5.為什麼要用異或運算符?

保證了對象的 hashCode 的 32 位值只要有一位發生改變,整個 hash() 返回值就會改變。盡可能的減少碰撞。

6.HashMap 的 table 的容量如何確定?loadFactor 是什麼?該容量如何變化?這種變化會帶來什麼問題?

①、table 數組大小是由 capacity 這個參數確定的,默認是16,也可以構造時傳入,最大限制是1<<30;

②、loadFactor 是裝載因子,主要目的是用來確認table 數組是否需要動態擴展,默認值是0.75,比如table 數組大小為 16,裝載因子為 0.75 時,threshold 就是12,當 table 的實際大小超過 12 時,table就需要動態擴容;

③、擴容時,調用 resize() 方法,將 table 長度變為原來的兩倍(注意是 table 長度,而不是 threshold)

④、如果數據很大的情況下,擴展時將會帶來性能的損失,在性能要求很高的地方,這種損失很可能很致命。

7.HashMap中put方法的過程?

答:“調用哈希函數獲取Key對應的hash值,再計算其數組下標;
如果沒有出現哈希衝突,則直接放入數組;如果出現哈希衝突,則以鏈表的方式放在鏈表後面;
如果鏈表長度超過閥值( TREEIFY THRESHOLD==8),就把鏈錶轉成紅黑樹,鏈表長度低於6,就把紅黑樹轉回鏈表;
如果結點的key已經存在,則替換其value即可;
如果集合中的鍵值對大於12,調用resize方法進行數組擴容。”

8.數組擴容的過程?

創建一個新的數組,其容量為舊數組的兩倍,並重新計算舊數組中結點的存儲位置。結點在新數組中的位置只有兩種,原下標位置或原下標+舊數組的大小。

9.拉鏈法導致的鏈表過深問題為什麼不用二叉查找樹代替,而選擇紅黑樹?為什麼不一直使用紅黑樹?

之所以選擇紅黑樹是為了解決二叉查找樹的缺陷,二叉查找樹在特殊情況下會變成一條線性結構(這就跟原來使用鏈表結構一樣了,造成很深的問題),遍歷查找會非常慢。

而紅黑樹在插入新數據后可能需要通過左旋,右旋、變色這些操作來保持平衡,引入紅黑樹就是為了查找數據快,解決鏈表查詢深度的問題,我們知道紅黑樹屬於平衡二叉樹,但是為了保持“平衡”是需要付出代價的,但是該代價所損耗的資源要比遍歷線性鏈表要少,所以當長度大於8的時候,會使用紅黑樹,如果鏈表長度很短的話,根本不需要引入紅黑樹,引入反而會慢。

10.說說你對紅黑樹的見解?

  • 每個節點非紅即黑
  • 根節點總是黑色的
  • 如果節點是紅色的,則它的子節點必須是黑色的(反之不一定)
  • 每個恭弘=叶 恭弘子節點都是黑色的空節點(NIL節點)
  • 從根節點到恭弘=叶 恭弘節點或空子節點的每條路徑,必須包含相同數目的黑色節點(即相同的黑色高度)

11.jdk8中對HashMap做了哪些改變?

在java 1.8中,如果鏈表的長度超過了8,那麼鏈表將轉換為紅黑樹。(桶的數量必須大於64,小於64的時候只會擴容)

發生hash碰撞時,java 1.7 會在鏈表的頭部插入,而java 1.8會在鏈表的尾部插入

在java 1.8中,Entry被Node替代(換了一個馬甲)。

12.HashMap,LinkedHashMap,TreeMap 有什麼區別?

HashMap 參考其他問題;

LinkedHashMap 保存了記錄的插入順序,在用 Iterator 遍歷時,先取到的記錄肯定是先插入的;遍歷比 HashMap 慢;

TreeMap 實現 SortMap 接口,能夠把它保存的記錄根據鍵排序(默認按鍵值升序排序,也可以指定排序的比較器)

13.HashMap & TreeMap & LinkedHashMap 使用場景?

一般情況下,使用最多的是 HashMap。

HashMap:在 Map 中插入、刪除和定位元素時;

TreeMap:在需要按自然順序或自定義順序遍歷鍵的情況下;

LinkedHashMap:在需要輸出的順序和輸入的順序相同的情況下。

14.HashMap 和 HashTable 有什麼區別?

①、HashMap 是線程不安全的,HashTable 是線程安全的;

②、由於線程安全,所以 HashTable 的效率比不上 HashMap;

③、HashMap最多只允許一條記錄的鍵為null,允許多條記錄的值為null,而 HashTable不允許;

④、HashMap 默認初始化數組的大小為16,HashTable 為 11,前者擴容時,擴大兩倍,後者擴大兩倍+1;

⑤、HashMap 需要重新計算 hash 值,而 HashTable 直接使用對象的 hashCode

15.Java 中的另一個線程安全的與 HashMap 極其類似的類是什麼?同樣是線程安全,它與 HashTable 在線程同步上有什麼不同?

ConcurrentHashMap 類(是 Java併發包 java.util.concurrent 中提供的一個線程安全且高效的 HashMap 實現)。

HashTable 是使用 synchronize 關鍵字加鎖的原理(就是對對象加鎖);

而針對 ConcurrentHashMap,在 JDK 1.7 中採用 分段鎖的方式;JDK 1.8 中直接採用了CAS(無鎖算法)+ synchronized。

16.HashMap & ConcurrentHashMap 的區別?

除了加鎖,原理上無太大區別。另外,HashMap 的鍵值對允許有null,但是ConCurrentHashMap 都不允許。

17.為什麼 ConcurrentHashMap 比 HashTable 效率要高?

HashTable 使用一把鎖(鎖住整個鏈表結構)處理併發問題,多個線程競爭一把鎖,容易阻塞;

ConcurrentHashMap

  • JDK 1.7 中使用分段鎖(ReentrantLock + Segment + HashEntry),相當於把一個 HashMap 分成多個段,每段分配一把鎖,這樣支持多線程訪問。鎖粒度:基於 Segment,包含多個 HashEntry。
  • JDK 1.8 中使用 CAS + synchronized + Node + 紅黑樹。鎖粒度:Node(首結點)(實現 Map.Entry)。鎖粒度降低了。

18.針對 ConcurrentHashMap 鎖機制具體分析(JDK 1.7 VS JDK 1.8)?

JDK 1.7 中,採用分段鎖的機制,實現併發的更新操作,底層採用數組+鏈表的存儲結構,包括兩個核心靜態內部類 Segment 和 HashEntry。

①、Segment 繼承 ReentrantLock(重入鎖) 用來充當鎖的角色,每個 Segment 對象守護每個散列映射表的若干個桶;

②、HashEntry 用來封裝映射表的鍵-值對;

③、每個桶是由若干個 HashEntry 對象鏈接起來的鏈表

JDK 1.8 中,採用Node + CAS + Synchronized來保證併發安全。取消類 Segment,直接用 table 數組存儲鍵值對;當 HashEntry 對象組成的鏈表長度超過 TREEIFY_THRESHOLD 時,鏈錶轉換為紅黑樹,提升性能。底層變更為數組 + 鏈表 + 紅黑樹。

19.ConcurrentHashMap 在 JDK 1.8 中,為什麼要使用內置鎖 synchronized 來代替重入鎖 ReentrantLock?

①、粒度降低了;

②、JVM 開發團隊沒有放棄 synchronized,而且基於 JVM 的 synchronized 優化空間更大,更加自然。

③、在大量的數據操作下,對於 JVM 的內存壓力,基於 API 的 ReentrantLock 會開銷更多的內存。

20.ConcurrentHashMap 簡單介紹?

①、重要的常量:

private transient volatile int sizeCtl;

當為負數時,-1 表示正在初始化,-N 表示 N – 1 個線程正在進行擴容;

當為 0 時,表示 table 還沒有初始化;

當為其他正數時,表示初始化或者下一次進行擴容的大小。

②、數據結構:

Node 是存儲結構的基本單元,繼承 HashMap 中的 Entry,用於存儲數據;

TreeNode 繼承 Node,但是數據結構換成了二叉樹結構,是紅黑樹的存儲結構,用於紅黑樹中存儲數據;

TreeBin 是封裝 TreeNode 的容器,提供轉換紅黑樹的一些條件和鎖的控制。

③、存儲對象時(put() 方法):

如果沒有初始化,就調用 initTable() 方法來進行初始化;

如果沒有 hash 衝突就直接 CAS 無鎖插入;

如果需要擴容,就先進行擴容;

如果存在 hash 衝突,就加鎖來保證線程安全,兩種情況:一種是鏈表形式就直接遍歷到尾端插入,一種是紅黑樹就按照紅黑樹結構插入;

如果該鏈表的數量大於閥值 8,就要先轉換成紅黑樹的結構,break 再一次進入循環

如果添加成功就調用 addCount() 方法統計 size,並且檢查是否需要擴容。

④、擴容方法 transfer():默認容量為 16,擴容時,容量變為原來的兩倍。

helpTransfer():調用多個工作線程一起幫助進行擴容,這樣的效率就會更高。

⑤、獲取對象時(get()方法):

計算 hash 值,定位到該 table 索引位置,如果是首結點符合就返回;

如果遇到擴容時,會調用標記正在擴容結點 ForwardingNode.find()方法,查找該結點,匹配就返回;

以上都不符合的話,就往下遍歷結點,匹配就返回,否則最後就返回 null。

21.ConcurrentHashMap 的併發度是什麼?

程序運行時能夠同時更新 ConccurentHashMap 且不產生鎖競爭的最大線程數。默認為 16,且可以在構造函數中設置。

當用戶設置併發度時,ConcurrentHashMap 會使用大於等於該值的最小2冪指數作為實際併發度(假如用戶設置併發度為17,實際併發度則為32)

更多精彩面試題

如果有想看的小夥伴就給我留言吧。這就是本文的全部內容了。如果覺得寫的不錯,請記得收藏加轉發。還想跟我看更多數據結構和算法題的小夥伴們,記得關注我公眾號:程序零世界,Java 就這麼回事。

線程,多線程,線程池,線程上下文,鎖一鍵啟動線程

紅黑樹其實並不難,只是你還沒看過ta

JVM其實並沒有那麼難,你也該啃下TA了

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

Typescript的interface、class和abstract class

interface,class,和abstract class這3個概念,既有聯繫,又有區別,本文嘗試着結合官方文檔來闡述這三者之間的關係。

1. Declaration Merging

Declaration Type Namespace Type Value
Namespace X X
Class X X
Enum X X
Interface X
Type Alias X
Function X
Variable X

首先我們來講一下上面這張表格,當我們第一列的關鍵字進行聲明時,我們在做什麼。

namespace job {
   haircut(): void;
}

class Man{
	name: string;
}
let imgss = new Man();

enum Color {red, blue, yellow}

interface dogfood {

  brand: string;
  price: number
}
type event = 'mouse' | 'keyboard';

function foo(){}

let a = 2;
var b = {};
const c = null;
	

namespace用來聲明一個命名空間,比較著名的命名空間有lodash,裏面有一堆工具函數,統統放在一個叫_的namespace裏面,同時你也可以let $ = _;所以namespace也聲明了一個值。

class聲明了一個值,也聲明了一種類型,你可以把Man賦值給一個變量,所以class是一種值,也可以說imgss是一個Man(類型),此時Man承擔了一種類型的角色。

enum聲明了一個值,也聲明了一種類型。我們說red是一種Color,Color在這裏承擔類型的角色,也可以把Color賦值給一個變量

interface聲明了一種類型,但是你不能把dogfood賦值給某個變量,否則你會得到一個報錯“dogfood’ only refers to a type, but is being used as a value here`

其他function,let,var,const都在聲明一個值,你 不能說xxx是一個a,或者xxx是一個foo,不能把值當成類型使用。

2. interface和class

我們知道,不算symbol,js中有6種基本類型,number,string,boolean,null, undefined, object。但是只依靠這幾種類型,來描述某個函數需要傳什麼樣的參數,是遠遠不夠的,這也是interface的使命–描述一個值(value)的形狀(type)。

現在我們來看class,class首先也具有interface的能力,描述一個形狀,或者說代表一種類型。此外class還提供了實現,也就是說可以被實例化;

所以class可以implements interface:

interface ManLike {
  speak(): void;
  leg: number;
  hand: number;
}
class Human implements ManLike {
  leg: number = 2;
  hand: number = 2;
  speak() {
    console.log('i can speak');
  }
}

而interface可以extends class,此時的class承擔類型的角色

interface Chinese extends Human {
  country: string;
}

那麼interface能不能extends enum或者type alias呢,這兩個兄弟也聲明了type啊,答案是不行的,官方報錯的信息:

An interface can only extend an object type or intersection of object types with statically known members.

3. class和abstract class

class和abstract class的區別主要是abstract class不能被實例化:

abstract Human {
	name: string;
    abstract lang(): void;
	toString() {
    	return `<human:${this.name}>`
    }
}
new Human // Cannot create an instance of an abstract class.

4. interface和abstract class

兩者都不能被實例化,但是abstract class 也可以被賦值給變量。
interface 裏面不能有方法的實現,abstract class 可以提供部分的方法實現,這些方法可以被子類調用。

參考: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

程序員的命名素養

引言

今天來聊聊命名相關內容。

在日常工作中,項目、類、方法、表等等等等,都需要我們起名來標識區分。好的名字讓人賞心悅目,不好的名字讓人看的想吐。

最近工作有幸寫了node、前端、php、sql、scala,也見識了公司各位前輩們的命名功底。其中不乏abc命名、拼音命名、蹩腳英文命名,更有不少從別的地方粘過來連名都不改的操作。

命名沒有對錯,只是規範一點,可以提高可讀性、可維護性。

命名原則

拼寫正確

拼寫正確是可讀的基礎。

play shiftplay shit自己體會一下

清新明了,見名知意

根據要表達的內容命名,一針見血。

getNameById 根據id獲取名稱
ClassLoader 類加載器
MYSQL_USERNAME mysql用戶名 

如上幾個例子,我們一眼就知道要表達什麼,可讀性高。

使用英文字母命名

在編程中,英文還是較為主流的,最好使用單詞來命名,再不濟也是用拼音來命名。

不論是拼音或單詞,清晰表意是首要。

保持一致

在一個項目中,應該使用統一的規範來命名。

無規矩不成方圓。

合理使用動詞名詞

類名、變量名通常應使用名詞。如ClassLoaderuserId

對於方法名、函數名,應包含動詞。如handleClickgenerateUniqueId

命名方法

常見的命名方法有駝峰命名法、匈牙利命名法、帕斯卡命名法、中/下劃線命名法

駝峰命名法Camel-Case

駝峰命名法,又叫小駝峰命名法,如名稱所表達的意思,指混合使用大小寫字母老表示名字。

userIdgetCompanyNameById

應用很廣泛。

匈牙利命名法

基本原則是:變量名=屬性+類型+對象描述。通過名稱可以直觀的了解他的所屬、類型等信息。

是早期的命名方式,早期IDE沒有很智能的時候,這種命名是很有必要的。

iNum,表示int類型的num

現在依舊很少有人用了。

帕斯卡命名法

又叫大駝峰命名法,就是把駝峰命名的首字母大寫了。

ClassLoader

中/下劃線命名法

單詞全部小寫,單詞和單詞間用中劃線或下劃線分割。

user_idpython-flask-demo

下劃線命名在數據庫中較為常見。

常量命名法

這個不是官方的方法,但是常量一般是由固定規範的。

格式:所有單詞的所有字母都是大寫,單詞之間用下戶線連接。

APOLLO_NAMESPAC

總結

好的命名習慣是每個程序員必備的基本素養。

寫代碼時,好的命名會讓思路更加清洗,代碼寫的更加絲滑。

代碼就是程序員的形象,從命名的細節開始,讓自己更帥一些。

個人公眾號:碼農峰,定時推送行業資訊,持續發布原創技術文章,歡迎大家關注。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

Web前端兼容性指南

一、Web前端兼容性問題

一直以來,Web前端領域最大的問題就是兼容性問題,沒有之一。

 

前端兼容性問題分三類:

  • 瀏覽器兼容性
  • 屏幕分辨率兼容性
  • 跨平台兼容性

 

1、瀏覽器兼容性問題

第一次瀏覽器大戰發生在上個世紀90年代,微軟發布了IE瀏覽器,和網景公司的Netscape Navigator大打出手,1998年網景不得不將公司賣給AOL。沒有了對手的IE不思進取,W3C標準支持發展緩慢,為以後的IE兼容性災難埋下了伏筆。到2004年,IE的市場份額達到95%,但在此之後IE的份額逐步遭其他瀏覽器蠶食,主要包括Firefox,Chrome,Safari和Opera。.

 

2001年8月27日,微軟發布IE6,時隔五年直到2006年才發布了IE7。2009年3月19日,經歷了眾多測試版后,IE8最終發布,雖然IE8針對舊版IE在多方面做了很大改進,但在HTML5、CSS 3等標準支持方面仍落後於其他瀏覽器對手。這三個版本的IE是所有兼容性問題的最大根源,堪稱前端噩夢。

 

IE6、7、8不支持HTML5、CSS3、SVG標準,可被判定為“極難兼容”

IE9不支持Flex、Web Socket、WebGL,可被判定為“較難兼容”

IE10部分支持Flex(-ms-flexbox)、Web Socket,可被判定為“較易兼容”

IE11部分支持Flex、WebGL,可被判定為“較易兼容”

 

IE6、7、8、9可視為“老式瀏覽器”

IE10、11可視為“准現代瀏覽器”

Chrome、Firefox、Safari、Opera 、Edge可視為“現代瀏覽器”

 

瀏覽器與Windows版本份額

Statcounter的各項數據以2020年6月為基準。

http://gsa.statcounter.com/

 

 

 2、屏幕分辨率兼容性問題

在不同的屏幕分辨率,瀏覽器頁面展示差異很大。特別是屏幕分辨率較小時,容易發生布局錯亂。為了解決這個問題,響應式UI框架應運而生。

 

主流桌面屏幕分辨率寬度集中在1280~1920,高度集中在720~1080;

主流平板屏幕分辨率寬度集中在962~1280,高度集中在601~800。

主流移動屏幕分辨率寬度集中在360~414,高度集中在640~896。

 

典型的桌面屏幕分辨率:1920×1080

典型的便攜屏幕分辨率:1366×768

典型的平板屏幕分辨率:768×1024

典型的移動屏幕分辨率:360×640

 

Bootstrap定義(參考系是邏輯分辨率):

分辨率

設備名

典型屏幕

>=1400px

xxl 超超大屏設備

桌面屏幕

>=1200px

xl 超大屏設備

便攜屏幕

>=992px

lg 大屏設備

豎屏桌面屏幕、橫屏平板屏幕

>=768px

md 中屏設備

豎屏平板屏幕

>=576px

sm 小屏設備

橫屏移動屏幕

<576px

xs 超小屏(自動)設備

豎屏移動屏幕

注:Bootstrap5新增xxl,Bootstrap3中的lg>=1200px,無576px檔。

 

手機屏幕分辨率說明

由於手機屏幕尺寸過小,使用原始分辨率會使得頁面显示過小,因此使用了邏輯分辨率,用倍數放大的方法來保證兼容性。比如iOS app的UI資源區分@1x、@2x和@3x,這就是指原始分辨率對邏輯分辨率的倍數,被稱為設備像素比DPR。所以大部分人的手機分辨率都是1080×1920,在分類中卻被歸為了360×640。這個分辨率和CSS中的PX是一致的。

 

桌面屏幕分辨率說明

移動設備一開始就考慮了DPR,而Windwos桌面的分辨率由於歷史原因卻沒有這一概念,於是Windwos引入了DPI,最初是設置DPI,後來是設置DPI比例。比如設置DPI比例=125%,你可以查詢Chrome的window.devicePixelRatio,這時輸出1.25,這說明DPI比例=DPR。但是大部分老程序並不支持DPI(Unaware),所以當你設置高DPI時,只能等比放大,字模糊到眼要瞎,最後落得空有大屏只能用超低分辨率。由於Chrome支持DPI,所以並不擔心Web有DPI問題。但需要注意的是與手機屏幕分辨率不同,桌面分辨率要除以DPI比例,才是邏輯分辨率。如1920×1080設置DPI比例=1.25,邏輯分辨率實際為1536×864。

  

  

屏幕分辨率基礎概念說明

縮寫

全稱

說明

PX

Device Pixels

設備像素,指設備的物理像素

PX

CSS Pixels

CSS像素,指CSS樣式代碼中使用的邏輯像素

DOT

Dot

點,屏幕或打印紙上的點,等同物理像素

PT

Point

磅(傳統長度單位)為1/72英寸=0.35mm

PT

iOS Point

磅(iOS長度單位),為1/163英寸,等同於CSS邏輯像素

DP

Density independent Pixels

設備無關像素(Android長度單位),為1/160英寸,等同於CSS邏輯像素

SP

Scale independent Pixels

縮放無關像素(Android字體單位),等同於CSS邏輯像素,但文字尺寸可調(單獨縮放)

DPR

Device Pixel Ratio

設備像素比,指CSS邏輯像素對於物理像素的倍數

DPPX

Dots Per Pixel

等同於DPR

PPI

Pixel Per Inch

屏幕上每英寸(2.54厘米)的像素點個數

DPI

Dots Per Inch

屏幕或紙上每英寸(2.54厘米)的點個數,標準密度:傳統打印=72;Windows=96;Android=160;iOS=163。

DPIR

DPI Ratio

DPI縮放比例,指DPI對於Windows標準DPI的倍數=DPI/96,等同於DPR

注:各廠商概念有重名現象,請注意區分。

 

各平台屏幕分辨率份額

  

3、跨平台兼容性問題 

隨着移動和平板市場的日益發展,Web在桌面、平板、移動平台上的兼容性問題日益突出。由於移動和平板是觸摸式操作,與桌面的鼠標操作方式有很大差異,因此在不同平台上要做相應修改。為了解決這個問題,誕生了跨平台框架,在不同平台上,外觀、布局、操作都有差異化修改。

 

各平台份額

  

二、前端里程碑框架

在前端領域,隨着技術的不斷進步,逐步誕生了一些里程碑式的前端框架。這些前端框架,大致也是隨着兼容性問題的發生、發展而誕生、發展的。

 

這些框架代表了前端應用當時先進、成熟、主流的開發方式與發展方向,兼容性問題也在這些框架的基礎之上不斷得到解決,大致也分為三個階段:

一、DOM操作框架,代表框架:jQuery

二、響應式框架,代表框架:Bootstrap

三、前端MVC框架,代表框架:React、Angular、Vue

 

1、JQuery

2006年1月John Resig等人創建了jQuery;8月,jQuery的第一個穩定版本。jQuery是DOM操作時代前端框架最優秀,也幾乎是唯一代表;但是在以React為代表的新式前端框架崛起之後,迅速沒落。

 

  • JQuery 1.x兼容IE6+瀏覽器
  • JQuery 2.x兼容IE9+瀏覽器
  • JQuery 3.x兼容IE9+瀏覽器

 

2、Bootstrap

Bootstrap原名Twitter Blueprint,由Mark Otto和Jacob Thornton開發,最經典的響應式CSS框架,在2011年8月19日作為開源項目發布。其核心是16列布局柵格系統,使用媒體查詢設定閾值為超小屏幕,小屏幕,中等屏幕,大屏幕,超大屏幕創建不同的樣式。

 

  • Bootstrap 2兼容IE7+瀏覽器
  • Bootstrap 3兼容IE8+瀏覽器
  • Bootstrap 4兼容IE10+瀏覽器
  • Bootstrap 5不兼容IE瀏覽器

 

3、React

React 起源於 Facebook 的內部項目,在前端MVC框架大潮中誕生並走紅。2013年5月開源,憑藉Virtual Dom,JSX,Flux,Native等一大批創新特性,迅速吸引了大量開發人員,至今仍是最先進的前端JS框架。

 

4、Angular

AngularJS 誕生於2009年,由Misko Hevery 等人創建,後為Google所收購。由於Google不差錢,所以AngularJS經歷顛覆性升級為Angular。Angular最大的特點就是大而全。

 

5、Vue

2013年,在Google工作的尤雨溪,受到Angular的啟發,從中提取自己所喜歡的部分,開發出了一款輕量框架,最初命名為Seed,后更名為Vue。

 

三、瀏覽器兼容框架

在前端發展的初期,大多數開發最關注的問題就是瀏覽器兼容問題,迫切需要兼容所有瀏覽器的JS和CSS框架。這階段除了橫空出世的jQuery,還有一些其它方面的兼容框架。

 

1、normalize.css

讓不同的瀏覽器在渲染網頁元素的時候形式更統一。

 

2、html5shiv.js

IE6~IE8識別HTML5標籤,並且可以添加CSS樣式。

 

3、respond.js

使IE6~IE8瀏覽器支持媒體查詢。

 

四、響應式框架

有了jQuery等兼容框架的基礎,開發人員的關注點,逐漸轉移到越來越豐富的屏幕分辨率上,除開Bootstrap一家獨大,越來越多的響應式框架也在奮起直追。

 

1、Semantic UI

https://github.com/semantic-org/semantic-ui

Semantic 是一個設計漂亮的響應式布局的語義化框架。

 

2、Bulma

https://github.com/jgthms/bulma

基於 Flexbox 的現代 CSS 框架

 

3、Tailwind

https://github.com/tailwindcss/tailwindcss

Tailwind是一個底層CSS 框架,快速 UI 開發的實用工具集,提供了高度可組合的應用程序類,可幫助開發者輕鬆構建複雜的用戶界面。另外Tailwind + Styled Component 簡直是絕配(摘自知乎https://www.zhihu.com/question/337939566)。

 

4、Materialize

https://github.com/Dogfalo/materialize

A CSS Framework based on Material Design.

 

5、Foundation

https://github.com/foundation/foundation-sites

The most advanced responsive front-end framework in the world.

 

6、Pure.css

https://github.com/pure-css/pure

A set of small, responsive CSS modules

 

7、YAMLCSS

https://github.com/yamlcss/yaml

YAML is a modular CSS framework for truly flexible, accessible and responsive websites.

 

兼容IE6+瀏覽器(能兼容IE6的太稀少了)

 

五、跨平台框架

自2009年以來,由於Node.js生態的不斷髮展,前端開發的勢力大漲, AngularJS,BackboneJS,KnockoutJS等一批前端MVC框架開始出現。最終伴隨着React、Angular、Vue等框架的脫穎而出,用前端框架開發移動、桌面應用的野心開始暴漲,開始關注不同平台的差異化,越來越多的跨平台框架開始出現。

 

1、Framework7

https://github.com/framework7io/framework7

Build iOS, Android & Desktop apps

 

 從上圖可以看出,桌面版本比移動版本更緊湊,控件風格跟所在平台近似。支持三種主題:ios、 md、 aurora對應不同平台。

 

2、Ionic

https://github.com/ionic-team/ionic

build mobile and desktop apps

 

 從上圖可以看出,主要針對移動平台優化,但通過API支持多種平台。

 

3、Onsen UI

https://github.com/OnsenUI/OnsenUI

develop HTML5 hybrid and mobile web apps

 

 從上圖可以看出,主要針對移動平台優化,但通過API支持多種平台。

 

4、Quasar Framework

https://github.com/quasarframework/quasar

基於Vue構建響應式網站、PWA、SSR、移動和桌面應用

 

 Quasar將一些輔助CSS類附加到document.body:如desktop、mobile、touch、platform-[ios]、within-iframe等


5、UNI-APP
 

https://github.com/dcloudio/uni-app

使用 Vue.js 開發所有前端應用的框架

 

 從上圖可以看出,三種平台比較一致,但移動版本還比桌面版本還緊湊是什麼意思?

 

6、橫向對比

框架

桌面優化

移動優化

移動一致

支持框架

Framework7

優秀

優秀

優秀

最多

Ionic

一般

優秀

一般

較多

Onsen UI

一般

優秀

一般

較多

Quasar

良好

優秀

良好

Vue

UNI-APP

一般

優秀

優秀

Vue

 

六、總結

兼容性問題總是伴隨着平台的擴張而產生的,Web開發面臨的終極問題就是多平台兼容性問題,根據不同產品,不同階段做部分取捨,應用不同的框架而已。需要支持的平台,決定了你的選擇。

 

新的框架或舊框架的新版本基本都不再支持IE,但國內還有5.65% 的IE用戶,而且3.29%的WinXP,46.79%的Win7都是潛在的IE用戶,所以可將其做為一個平台看待。

  • IE Web
  • Desktop Web
  • Mobile Web
  • Tablet Web
  • Desktop Hybrid
  • Mobile Hybrid
  • Tablet Hybrid

注:React Native代表的Native技術不在本次討論之列

 

1、瀏覽器兼容策略

國內XP用戶還有3.29%,XP用戶既升級不了IE9,也無法安裝新版本Chrome和Firefox 。而IE用戶還有 5.65%,考慮到Windows用戶為87%,所以IE9+的份額應該要少於5.65%-3.29%*87%=2.79%。也就是說IE8以下的用戶要多於IE8以上的用戶。所以支持單獨支持IE9+ 瀏覽器沒有實際意義,要麼支持IE6,要麼不支持IE,。

 

看看知名網站對IE8的兼容性,

  • 京東會提示“溫馨提示:您當前的瀏覽器版本過低,存在安全風險,建議升級瀏覽器”,但是頁面完全可以正確显示,幾乎沒有什麼異常發生,看來兼容工作很到位。
  • 淘寶會出現很多頁面異常,說明IE兼容工作要求不高,基本正常即可,只是象徵性的加了幾條兼容性內容。
  • 去哪兒網也會出現很多頁面異常,但頁面布局還是正常的,看來也是儘力而為,不做要求。
  • 騰訊的頁面只有一個立即更新按鈕,一貫地友好。
  • 知乎直接404,好吧,強大。

 

兼容IE的建議:

一、建議不做任何兼容,IE6~11直接显示升級瀏覽器按鈕。

二、如果一定要兼容,後端返回IE專用頁面,至少兼容IE8。

 

2、屏幕分辨率兼容策略

屏幕分辨率最少要考慮兼容便攜屏幕和移動屏幕兩種。可以參考去哪兒網的做法,把內容分成三類:移動端主菜單與導航欄;主要內容;擴展內容。屏幕分辨率高於480,显示主要內容、擴展內容。屏幕分辨率低於480,显示移動端主菜單與導航欄、主要內容。

 

如果你的應用是管理軟件,則最好考慮兼容桌面屏幕、便攜屏幕和移動屏幕三種。Bootstrap5新增了超超大屏幕,則就是基於這種考慮。這時候,可以加入側邊欄自動隱藏/打開,主要內容用Flex方式組織,可以在頁面中並排显示多頁(類似於Word的頁面視圖)。

 

3、跨平台兼容策略

大型網站,手機網站與桌面網站是不同的入口,因此不存在兼容,是兩個單獨的應用程序。對於流量較小的網站,平台的兼容策略主要是應用響應式框架,加上移動端主菜單與導航欄即可,其次可以選用跨平台框架來實現在不同平台的差異化體驗。沒有這些框架對於Web網站來說不造成大的體驗下降。而如果需要開發混合移動、桌面應用,則需要認真考慮這些框架,畢竟用戶對本地應用的體驗期待要高很多。

 

 (全文完)

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

EM(最大期望)算法推導、GMM的應用與代碼實現

  EM算法是一種迭代算法,用於含有隱變量的概率模型參數的極大似然估計。

使用EM算法的原因

  首先舉李航老師《統計學習方法》中的例子來說明為什麼要用EM算法估計含有隱變量的概率模型參數。

  假設有三枚硬幣,分別記作A, B, C。這些硬幣正面出現的概率分別是$\pi,p,q$。進行如下擲硬幣試驗:先擲硬幣A,根據其結果選出硬幣B或C,正面選硬幣B,反面邊硬幣C;然後擲選出的硬幣,擲硬幣的結果出現正面記作1,反面記作0;獨立地重複$n$次試驗,觀測結果為$\{y_1,y_2,…,y_n\}$。問三硬幣出現正面的概率。

  三硬幣模型(也就是第二枚硬幣正反面的概率)可以寫作

$ \begin{aligned} &P(y|\pi,p,q) \\ =&\sum\limits_z P(y,z|\pi,p,q)\\ =&\sum\limits_z P(y|z,\pi,p,q)P(z|\pi,p,q)\\ =&\pi p^y(1-p)^{1-y}+(1-\pi)q^y(1-q)^{1-y} \end{aligned} $

  其中$z$表示硬幣A的結果,也就是前面說的隱變量。通常我們直接使用極大似然估計,即最大化似然函數

$ \begin{aligned} &\max\limits_{\pi,p,q}\prod\limits_{i=1}^n P(y_i|\pi,p,q) \\ =&\max\limits_{\pi,p,q}\prod\limits_{i=1}^n[\pi p^{y_i}(1-p)^{1-y_i}+(1-\pi)q^{y_i}(1-q)^{1-y_i}]\\ =&\max\limits_{\pi,p,q}\sum\limits_{i=1}^n\log[\pi p^{y_i}(1-p)^{1-y_i}+(1-\pi)q^{y_i}(1-q)^{1-y_i}]\\ =&\max\limits_{\pi,p,q}L(\pi,p,q) \end{aligned} $

  分別對$\pi,p,q$求偏導並等於0,求解線性方程組來估計這三個參數。但是,由於它是帶有隱變量的,在獲取最終的隨機變量之前有一個分支選擇的過程,導致這個$\log$的內部是加和的形式,計算導數十分困難,而待求解的方程組不是線性方程組。當複雜度一高,解這種方程組幾乎成為不可能的事。以下推導EM算法,它以迭代的方式來求解這些參數,應該也算一種貪心吧。

算法導出與理解

  對於參數為$\theta$且含有隱變量$Z$的概率模型,進行$n$次抽樣。假設隨機變量$Y$的觀察值為$\mathcal{Y} = \{y_1,y_2,…,y_n\}$,隱變量$Z$的$m$個可能的取值為$\mathcal{Z}=\{z_1,z_2,…,z_m\}$。

  寫出似然函數:

$ \begin{aligned} L(\theta) &= \sum\limits_{Y\in\mathcal{Y}}\log P(Y|\theta)\\ &=\sum\limits_{Y\in\mathcal{Y}}\log \sum\limits_{Z\in \mathcal{Z}} P(Y,Z|\theta)\\ \end{aligned} $

  EM算法首先初始化參數$\theta = \theta^0$,然後每一步迭代都會使似然函數增大,即$L(\theta^{k+1})\ge L(\theta^k)$。如何做到不斷變大呢?考慮迭代前的似然函數(為了方便不用$\theta^{k+1}$):

$ \begin{gather} \begin{aligned} L(\theta)=&\sum\limits_{Y\in \mathcal{Y}} \log\sum\limits_{Z\in \mathcal{Z}} P(Y,Z|\theta)\\ =&\sum\limits_{Y\in \mathcal{Y}} \log\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\frac{P(Y,Z|\theta)}{P(Z|Y,\theta^k)}\\ \end{aligned} \label{} \end{gather} $

  至於上式的第二個等式為什麼取出$P(Z|Y,\theta^k)$而不是別的,正向的原因我想不出來,馬後炮原因在後面記錄。

  考慮其中的求和

$ \sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)=1$

  且由於$\log$函數是凹函數,因此由Jenson不等式得

$ \begin{gather} \begin{aligned} L(\theta) \ge&\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log\frac{P(Y,Z|\theta)}{P(Z|Y,\theta^k)}\\ =&B(\theta,\theta^k) \end{aligned}\label{} \end{gather} $

  當$\theta = \theta^k$時,有

$ \begin{gather} \begin{aligned} L(\theta^k) \ge& B(\theta^k,\theta^k)\\ =&\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log\frac{P(Y,Z|\theta^k)}{P(Z|Y,\theta^k)}\\ =&\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log P(Y|\theta^k)\\ =&\sum\limits_{Y\in \mathcal{Y}}\log P(Y|\theta^k)\\ =&L(\theta^k)\\ \end{aligned} \label{} \end{gather} $

  也就是在這時,$(2)$式取等,即$L(\theta^k) = B(\theta^k,\theta^k)$。取

$ \begin{gather} \theta^*=\text{arg}\max\limits_{\theta}B(\theta,\theta^k)\label{} \end{gather} $

  可得不等式

$L(\theta^*)\ge B(\theta^*,\theta^k)\ge B(\theta^k,\theta^k) = L(\theta^k)$

  所以,我們只要優化$(4)$式,讓$\theta^{k+1} = \theta^*$,即可保證每次迭代的非遞減勢頭,有$L(\theta^{k+1})\ge L(\theta^k)$。而由於似然函數是概率乘積的對數,一定有$L(\theta) < 0$,所以迭代有上界並且會收斂。以下是《統計學習方法》中EM算法一次迭代的示意圖:

  進一步簡化$(4)$式,去掉優化無關項:

$ \begin{aligned} \theta^*=&\text{arg}\max\limits_{\theta}B(\theta,\theta^k) \\ =&\text{arg}\max\limits_{\theta}\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log\frac{P(Y,Z|\theta)}{P(Z|Y,\theta^k)} \\ =&\text{arg}\max\limits_{\theta}\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log P(Y,Z|\theta) \\ =&\text{arg}\max\limits_{\theta}Q(\theta,\theta^k) \\ \end{aligned} $

  $Q$函數使用導數求極值的方程與沒有隱變量的方程類似,容易求解。

  綜上,EM算法的流程為:

  1. 設置$\theta^0$的初值。EM算法對初值是敏感的,不同初值迭代出來的結果可能不同。

  2. 更新$\theta^k = \text{arg}\max\limits_{\theta}Q(\theta,\theta^{k-1})$。理解上來說,通常將這一步分為計算$Q$與極大化$Q$兩步,即求期望E與求極大M,但在代碼中並不會將它們分出來,因此這裏濃縮為一步。另外,如果這個優化很難計算的話,因為有不等式的保證,直接取$\theta^k$為某個$\hat{\theta}$,只要有$Q(\hat{\theta},\theta^{k-1})\ge Q(\theta^{k-1},\theta^{k-1})$即可。

  3. 比較$\theta^k$與$\theta^{k-1}$的差異,比如求它們的差的二范數,若小於一定閾值就結束迭代,否則重複步驟2。

  下面記錄一下我對$(1)$式取出$P(Z|Y,\theta^k)$而不取別的$P$的理解:

  經過以上的推導,我認為這是為了給不等式取等創造條件。如果不能確定$L(\theta^k)$與$Q(\theta^k,\theta^k)$能否取等,那麼取$Q$的最大值$Q(\theta^*,\theta^k)$時,儘管有$Q(\theta^*,\theta^k)\ge Q(\theta^k,\theta^k)$,但並不能保證$L(\theta^*)\ge L(\theta^k)$,迭代的不減性質就就沒了。

  我這裏暫且把它看做一種巧合,是研究EM算法的大佬,碰巧想用Jenson不等式來迭代而構造出來的一種做法。本人段位還太弱,無法正向理解其中的緣故,只能以這種方式來揣度大佬的思路了。知乎大佬發的EM算法九層理解(點擊鏈接),我當前只能到第3層,有時間一定要拜讀一下深度學習之父的著作。

高斯混合模型的應用

迭代式推導

  假設高斯混合模型混合了$m$個高斯分佈,參數為$\theta = (\alpha_1,\theta_1,\alpha_2,\theta_2,…,\alpha_m,\theta_m),\theta_i=(\mu_i,\sigma_i)$則整個概率分佈為:

$\displaystyle P(y|\theta) = \sum\limits_{i=1}^m\alpha_i \phi(y|\theta_i) =  \sum\limits_{i=1}^m\frac{\alpha_i }{\sqrt{2\pi}\sigma_i}\exp\left(-\frac{(y-\mu_i)^2}{2\sigma_i^2}\right),\;\text{where}\;\sum\limits_{j=1}^m\alpha_j = 1$

  對混合分佈抽樣$n$次得到$\{y_1,…,y_n\}$,則在第$k+1$次迭代,待優化式為:

$\begin{gather}\begin{aligned} &\max\limits_{\theta}Q(\theta,\theta^k) \\ =&\max\limits_{\theta}\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta^k)\log P(Y,Z|\theta) \\ =&\max\limits_{\theta}\sum\limits_{Y\in \mathcal{Y}}\sum\limits_{Z\in \mathcal{Z}} \frac{P(Z,Y|\theta^k)}{P(Y|\theta^k)}\log P(Y,Z|\theta) \\ =&\max\limits_{\theta}\sum\limits_{i=1}^n\sum\limits_{j=1}^m \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)} \log \left[\alpha_j\phi(y_i|\theta_j)\right] \\ =&\max\limits_{\theta}\sum\limits_{i=1}^n\sum\limits_{j=1}^m \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)} \log \left[ \frac{\alpha_j}{\sqrt{2\pi}\sigma_j}\exp\left(-\frac{(y_i-\mu_j)^2}{2\sigma_j^2}\right) \right]\\ =&\max\limits_{\theta}\sum\limits_{j=1}^m \sum\limits_{i=1}^n \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)} \left[ \log \alpha_j – \log \sigma_j-\frac{(y_i-\mu_j)^2}{2\sigma_j^2} \right]\\  \end{aligned} \label{}\end{gather}$

計算α

  定義

$\displaystyle n_j = \sum\limits_{i=1}^n \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)}$

  則對於$\alpha$,優化式為

$\begin{gather} \begin{aligned} \max\limits_{\alpha}\sum\limits_{j=1}^m n_j \log \alpha_j \end{aligned} \label{}\end{gather}$

  又因為$\sum\limits_{j=1}^m \alpha_j=1$,所以只需優化$m-1$個參數,上式變為:

$ \max\limits_\alpha \left[ \begin{matrix} n_1&n_2&\cdots &n_{m-1}&n_{m}\\ \end{matrix} \right] \cdot \left[ \begin{matrix} \log\alpha_1\\ \log\alpha_2\\ \vdots\\ \log\alpha_{m-1}\\ \log(1-\alpha_1-\cdots-\alpha_{m-1})\\ \end{matrix} \right] $

  對每個$\alpha_j$求導並等於0,得到線性方程組:

$\left[\begin{matrix}n_1+n_m&n_1&n_1&\cdots&n_1\\n_2&n_2+n_m&n_2&\cdots&n_2\\n_3&n_3&n_3+n_m&\cdots&n_3\\&&&\vdots&\\n_{m-1}&n_{m-1}&n_{m-1}&\cdots&n_{m-1}+n_m\\\end{matrix}\right]\cdot\left[\begin{matrix}\alpha_1\\\alpha_2\\\alpha_3\\\vdots\\\alpha_{m-1}\\\end{matrix}\right]=\left[\begin{matrix}n_1\\n_2\\n_3\\\vdots\\n_{m-1}\\\end{matrix}\right]$

  求解這個爪形線性方程組,得到

$\left[\begin{matrix}\sum_{j=1}^mn_j/n_1&0&0&\cdots&0\\-n_2/n_1&1&0&\cdots&0\\-n_3/n_1&0&1&\cdots&0\\&&&\vdots&\\-n_{m-1}/n_1&0&0&\cdots&1\\\end{matrix}\right]\cdot\left[\begin{matrix}\alpha_1\\\alpha_2\\\alpha_3\\\vdots\\\alpha_{m-1}\\\end{matrix}\right]=\left[\begin{matrix}1\\0\\0\\\vdots\\0\\\end{matrix}\right]$

  因為

$\displaystyle \sum\limits_{j=1}^m n_j =   \sum\limits_{j=1}^m\sum\limits_{i=1}^n \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)}=\sum\limits_{i=1}^n \sum\limits_{j=1}^m \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)} =\sum\limits_{i=1}^n 1 =  n$

  解得

$\displaystyle\alpha_j = \frac{n_j}{n} = \frac{1}{n}\sum\limits_{i=1}^n \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)}$

計算σ與μ

  與$\alpha$不同,它的方程組是所有$\alpha_j$之間聯立的;而$\sigma,\mu$的方程組則是$\sigma_j$與$\mu_j$之間聯立的。定義

$\displaystyle p_{ji} = \frac{\alpha_j^k\phi(y_i|\theta_j^k)} {\sum\limits_{l=1}^m \alpha_l^k\phi(y_i|\theta_l^k)}$

  則對於$\sigma_j,\mu_j$,優化式為(比較$(6),(7)$式的區別)

$\begin{gather}\displaystyle\min\limits_{\sigma_j,\mu_j}\sum\limits_{i=1}^n p_{ji} \left(\log \sigma_j+\frac{(y_i-\mu_j)^2}{2\sigma_j^2} \right)\label{}\end{gather}$

  對上式求導等於0,解得

$ \begin{aligned} &\mu_j = \frac{\sum\limits_{i=1}^np_{ji}y_i}{\sum\limits_{i=1}^np_{ji}} = \frac{\sum\limits_{i=1}^np_{ji}y_i}{n_j} = \frac{\sum\limits_{i=1}^np_{ji}y_i}{n\alpha_j}\\ &\sigma^2_j = \frac{\sum\limits_{i=1}^np_{ji}(y_i-\mu_j)^2}{\sum\limits_{i=1}^np_{ji}} = \frac{\sum\limits_{i=1}^np_{ji}(y_i-\mu_j)^2}{n_j} = \frac{\sum\limits_{i=1}^np_{ji}(y_i-\mu_j)^2}{n\alpha_j} \end{aligned} $

代碼實現

  對於概率密度為$P(x) = −2x+2,x\in (0,1)$的隨機變量,以下代碼實現GMM對這一概率密度的的擬合。共10000個抽樣,GMM混合了100個高斯分佈。

#%%定義參數、函數、抽樣
import numpy as np
import matplotlib.pyplot as plt

dis_num = 100 #用於擬合的分佈數量
sample_num = 10000 #用於擬合的分佈數量
alphas = np.random.rand(dis_num) 
alphas /= np.sum(alphas)  
mus = np.random.rand(dis_num)
sigmas = np.random.rand(dis_num)**2#方差,不是標準差
samples = 1-(1-np.random.rand(sample_num))**0.5 #樣本
C_pi = (2*np.pi)**0.5

dis_val = np.zeros([sample_num,dis_num])    #每個樣本在每個分佈成員上都有值,形成一個sample_num*dis_num的矩陣
pij = np.zeros([sample_num,dis_num])        #pij矩陣
def calc_dis_val(sample,alpha,mu,sigma,c_pi):
    return alpha*np.exp(-(sample[:,np.newaxis]-mu)**2/(2*sigma))/(c_pi*sigma**0.5) 
def calc_pij(dis_v):  
    return dis_v / dis_v.sum(axis = 1)[:,np.newaxis]      
#%%優化 
for i in range(1000):
    print(i)
    dis_val = calc_dis_val(samples,alphas,mus,sigmas,C_pi)
    pij = calc_pij(dis_val)  
    nj = pij.sum(axis = 0)
    alphas_before = alphas
    alphas = nj / sample_num
    mus = (pij*samples[:,np.newaxis]).sum(axis=0)/nj
    sigmas = (pij*(samples[:,np.newaxis] - mus)**2 ).sum(axis=0)/nj
    a = np.linalg.norm(alphas_before - alphas)
    print(a)
    if  a< 0.001:
        break

#%%繪圖 
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常显示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常显示負號
def get_dis_val(x,alpha,sigma,mu,c_pi):
    y = np.zeros([len(x)]) 
    for a,s,m in zip(alpha,sigma,mu):   
        y += a*np.exp(-(x-m)**2/(2*s))/(c_pi*s**0.5)   
    return y
def paint(alpha,sigma,mu,c_pi,samples):
    x = np.linspace(-1,2,500)
    y = get_dis_val(x,alpha,sigma,mu,c_pi) 
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.hist(samples,density = True,label = '抽樣分佈') 
    ax.plot(x,y,label = "擬合的概率密度")
    ax.legend(loc = 'best')
    plt.show()
paint(alphas,sigmas,mus,C_pi,samples)

  以下是擬合結果圖,有點像是核函數估計,但是完全不同:

EM算法的推廣

  EM算法的推廣是對EM算法的另一種解釋,最終的結論是一樣的,它可以使我們對EM算法的理解更加深入。它也解釋了我在$(1)$式下方提出的疑問:為什麼取出$P(Z|Y,\theta^k)$而不是別的。

  定義$F$函數,即所謂Free energy自由能(自由能具體是啥先不研究了):

$ \begin{aligned} F(\tilde{P},\theta) &= E_{\tilde{P}}(\log P(Y,Z|\theta)) + H(\tilde{P})\\ &= \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log P(Y,Z|\theta) – \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log \tilde{P}(Z)\\ \end{aligned} $

  其中$\tilde{P}$是$Z$的某個概率分佈(不一定是單獨的分佈,可能是在某個條件下的分佈),$E_{\tilde{P}}$表示分佈$\tilde{P}$下的期望,$H$表示信息熵。

  我們計算一下,對於固定的$\theta$,什麼樣的$\tilde{P}$會使$F(\tilde{P},\theta) $最大。也就是找到一個函數$\tilde{P}_{\theta}$,使$F$極大,寫成優化的形式就是(這裡是找函數而不是找參數哦,理解上可能要用到泛函分析的內容):

$ \begin{aligned} &\max\limits_{\tilde{P}} \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log P(Y,Z|\theta) – \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log \tilde{P}(Z)\\ &\;\text{s.t.}\; \sum\limits_{Z\in \mathcal{Z}}\tilde{P}(Z) = 1 \end{aligned} $

  拉格朗日函數(拉格朗日對偶性,點擊鏈接)為:

$ \begin{aligned} L =  \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log P(Y,Z|\theta) – \sum\limits_{Z\in \mathcal{Z}} \tilde{P}(Z)\log \tilde{P}(Z)+ \lambda\left(1-\sum\limits_{Z\in \mathcal{Z}}\tilde{P}(Z)\right) \end{aligned} $

  因為每個$\tilde{P}(Z)$之間都是求和,沒有其它其它諸如乘積的操作,所以可以直接令$L$對某個$\tilde{P}(Z)$求導等於$0$來計算極值:

$ \begin{aligned} \frac{\partial L}{\partial \tilde{P}(Z)} = \log P(Y,Z|\theta) – \log \tilde{P}(Z) -1 -\lambda = 0 \end{aligned} $

  於是可以推出:

$ \begin{aligned} P(Y,Z|\theta) = e^{1+\lambda}\tilde{P}(Z) \end{aligned} $

  又由約束$\sum\limits_{Z\in \mathcal{Z}}\tilde{P}(Z) = 1$:

$P(Y|\theta) = e^{1+\lambda}$

  於是得到

$\begin{gather}\tilde{P}_{\theta}(Z) = P(Z|Y,\theta)\label{}\end{gather}$

  代回$F(\tilde{P},\theta)$,得到

$ \begin{aligned} F(\tilde{P}_\theta,\theta) &= \sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta)\log P(Y,Z|\theta) – \sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta)\log P(Z|Y,\theta)\\ &= \sum\limits_{Z\in \mathcal{Z}} P(Z|Y,\theta)\log \frac{P(Y,Z|\theta)}{P(Z|Y,\theta)}\\ &= \log P(Y|\theta)\\ \end{aligned} $

  也就是說,對$F$關於$\tilde{P}$進行最大化后,$F$就是待求分佈的對數似然;然後再關於$\theta$最大化,也就算得了最終要估計的參數$\hat{\theta}$。所以,EM算法也可以解釋為$F$的極大-極大算法。優化結果$(8)$式也解釋了我之前在$(1)$式下方的提問。

  那麼,怎麼使用$F$函數進行估計呢?還是要用迭代來算,迭代方式是和前面介紹的一樣的(懶得記錄了,統計學習方法上直接看吧)。實際上,$F$函數的方法只是提供了EM算法的另一種解釋,具體方法上並沒有提升之處。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案