em博客源碼
㈠ jQuery源碼分析之實例find和filter方法的區別七問
filter()過濾DOM元素包裝集,是指操作當前元素集,刪除不匹配的元素,得到一個新的集合
$('div').filter('.div1');//選擇div標簽中class屬性為div1的div元素
find()在當前選中元素的上下文中找到符合條件的後代,返回的是子元素
$('div').find('em');//選擇div標簽中的em標簽的元素
filter()是對選中的元素集合操作,得到這些元素中符合條件的元素,而find()是得到選中元素 中符合條件的後代子元素。
㈡ 簡易c++鬥地主源碼,簡單的鬥地主不需要ui,只要能發牌,隨機決定地主,把牌按大小順序排列
#include <time.h>
#include <iostream>
#include <string>
#include <vector>
enum em_CardClass_t
{
_CC_hearts = 0, // 紅桃
_CC_Spade, // 黑桃
_CC_Clubs, // 梅花
_CC_Diamonds, // 方塊
_CC_King // 大小王
};
struct st_Card_t
{
em_CardClass_t _emCardClass;
UINT _uCardIndex; // _emCardClass為_CC_King時,有效取值[1,2]
// _emCardClass非_CC_King時,有效取值[1,13]
};
using namespace std;
void InitCard(vector<st_Card_t>& vtCard)
{
st_Card_t card;
for( UINT i=0; i<_CC_King; i++ )
{
card._emCardClass = (em_CardClass_t)i;
for( UINT j=1; j<14; j++ )
{
card._uCardIndex = j;
vtCard.push_back(card);
}
}
card._emCardClass = _CC_King;
card._uCardIndex = 1;
vtCard.push_back(card);
card._uCardIndex = 2;
vtCard.push_back(card);
}
// 分牌
void DealCard(vector<st_Card_t>& vtCard, vector<st_Card_t>& vtPlayer1,
vector<st_Card_t>& vtPlayer2, vector<st_Card_t>& vtPlayer3)
{
srand( (unsigned)time( NULL ) );
for( int i = 0; i < 51; i++ )
{
int iCard = rand() % vtCard.size();
switch( i % 3 )
{
case 0:
vtPlayer1.push_back(vtCard[iCard]);
break;
case 1:
vtPlayer2.push_back(vtCard[iCard]);
break;
default:
vtPlayer3.push_back(vtCard[iCard]);
break;
}
if( iCard != vtCard.size()-1 )
{
vtCard[iCard] = vtCard[vtCard.size()-1];
}
vtCard.pop_back();
}
}
// 叫牌
int Bid(vector<st_Card_t>& vtCard, vector<st_Card_t>& vtPlayer1,
vector<st_Card_t>& vtPlayer2, vector<st_Card_t>& vtPlayer3)
{
srand( (unsigned)time( NULL ) );
int iBider = rand() % 3; // 叫牌者,也就是地主
vector<st_Card_t>* pPlayer = NULL;
switch( iBider )
{
case 0:
pPlayer = &vtPlayer1;
break;
case 1:
pPlayer = &vtPlayer2;
break;
default:
pPlayer = &vtPlayer3;
break;
}
for( UINT i = 0; i < vtCard.size(); i++ )
{
pPlayer->push_back(vtCard[i]);
}
return iBider;
}
// 整牌(按紅桃、黑桃、梅花、方塊、小大王的花色順序整理,同一花色再按從小到大的順序整理)
void SortCard(vector<st_Card_t>& vtPlayer)
{
st_Card_t tmp;
for( UINT i=0; i<vtPlayer.size()-1; i++ )
{
for( UINT j=i+1; j<vtPlayer.size(); j++ )
{
if( vtPlayer[i]._emCardClass < vtPlayer[j]._emCardClass )
{
continue;
}
if( vtPlayer[i]._emCardClass == vtPlayer[j]._emCardClass &&
vtPlayer[i]._uCardIndex < vtPlayer[j]._uCardIndex )
{
continue;
}
tmp = vtPlayer[i];
vtPlayer[i] = vtPlayer[j];
vtPlayer[j] = tmp;
}
}
}
void PrintPlayerCard(const string& sPlayerName,
const vector<st_Card_t>& vtPlayer)
{
cout << sPlayerName << " cards:" << endl;
for( UINT i=0; i< vtPlayer.size(); i++ )
{
switch( vtPlayer[i]._emCardClass )
{
case _CC_hearts:
cout << "紅桃";
break;
case _CC_Spade:
cout << "黑桃";
break;
case _CC_Clubs:
cout << "梅花";
break;
case _CC_Diamonds:
cout << "方塊";
break;
default:
cout << "King";
break;
}
cout << vtPlayer[i]._uCardIndex<< " ";
}
cout << endl << endl;
}
void main()
{
vector<st_Card_t> vtCard;
vector<st_Card_t> vtPlayer1;
vector<st_Card_t> vtPlayer2;
vector<st_Card_t> vtPlayer3;
InitCard(vtCard);
DealCard(vtCard, vtPlayer1, vtPlayer2, vtPlayer3);
int iBider = Bid(vtCard, vtPlayer1, vtPlayer2, vtPlayer3);
SortCard(vtPlayer1);
SortCard(vtPlayer2);
SortCard(vtPlayer3);
PrintPlayerCard("Player1", vtPlayer1);
PrintPlayerCard("Player2", vtPlayer2);
PrintPlayerCard("Player3", vtPlayer3);
cout <<"地主是Player"<< iBider+1 << endl << endl;
}
㈢ 這個鏈接下的源代碼是什麼
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>合租女孩洗澡不關門,用手機拍了幾張相片。。【好圖共賞】 |女人心情_ 搖籃論壇 </title>
<meta name="keywords" content="" />
<meta name="description" content=" 搖籃論壇 " />
<link rel="archives" title="搖籃論壇" href="http://bbs.yaolan.com/archiver/" />
<link href="http://loginbar.yaolan.com/css/dh.css" rel="stylesheet" type="text/css" />
<style type="text/css">
.dh_nav_r_m .menu input{ margin-top:6px;padding:0;}
</style>
<link rel="stylesheet" type="text/css" href="forumdata/cache/style_7_viewthread.css" />
<link rel="stylesheet" type="text/css" href="forumdata/cache/style_7_common.css" />
<script type="text/javascript">
var discuz_uid = 0;var IMGDIR = 'images/default';var attackevasive = '0';var gid = 0;var STYLEID = '7';
gid = parseInt('204');var fid = parseInt('24');var tid = parseInt('51269126');
</script>
<script src="include/javascript/common.js" type="text/javascript"></script>
<script src="http://bbs.yaolan.com/Js/jAppear.js?v=20081030" type="text/javascript"></script>
<link href="http://bbs.yaolan.com/css/Popo.css?v=20081030" rel="stylesheet" type="text/css" />
</head>
<body onkeydown="if(event.keyCode==27) return false;" onload="ShopAuth(3,'onload');">
<div id="menuinfo" >
<div id="nav_nav">
<script src="http://loginbar.yaolan.com/GetUserInfo.aspx" type="text/javascript"></script>
<script src="http://my.yaolan.com/Message/GetNewInfosCount1.aspx" type="text/javascript"></script>
<script src="http://loginbar.yaolan.com/js/loginbar.js" type="text/javascript"></script>
<ul style="width:450px">
<li class="menu1 wc_nav_bg1"><a href="http://www.yaolan.com/" target="_blank" class="wc_nav_nav">搖籃首頁</a></li>
<li class="menu1 wc_nav_bg1"><a href="http://abc.yaolan.com/" target="_blank" class="wc_nav_nav">成長階梯</a></li>
<li class="menu1 wc_nav_bg1"><a href="http://www.yaolan.com/index/" target="_blank" class="wc_nav_nav">育兒知識</a></li>
<li class="menu2 wc_nav_bg2" onmouseover="this.className='menu1 wc_nav_bg2'" onmouseout="this.className='menu2 wc_nav_bg2'">
<a href="http://ask.yaolan.com/" target="_blank" class="wc_nav_nav">育兒問答</a>
<div class="list">
<a href="http://www.1.yaolan.com/shequ/chat/index.asp" target="_blank">專家在線</a><br />
</div>
</li>
<li class="menu2 wc_nav_bg2" onmouseover="this.className='menu1 wc_nav_bg2'" onmouseout="this.className='menu2 wc_nav_bg2'">
<a href="http://baobao.yaolan.com/" target="_blank" class="wc_nav_nav">寶貝主頁</a>
<div class="list">
<a href="http://baobao.yaolan.com/jsp/bloglist/list.jsp" target="_blank">寶寶日記</a><br />
<a href="http://cn.yaolan.com/cn/" target="_blank">寶寶域名</a><br />
<a href="http://diy.yaolan.com/" target="_blank">個性定製</a><br />
<a href="http://bless.yaolan.com/getKnot.aspx" target="_blank">送祝福</a><br />
</div>
</li>
<li class="menu1 wc_nav_bg1"><a href="http://bbs.yaolan.com/" target="_blank" class="wc_nav_nav">
育兒論壇</a></li>
<li class="menu2 wc_nav_bg2" onmouseover="this.className='menu1 wc_nav_bg2'" onmouseout="this.className='menu2 wc_nav_bg2'">
<a href="http://emag.yaolan.com/" target="_blank" class="wc_nav_nav">電子雜志</a>
<div class="list">
<a href="http://emag.yaolan.com/ezine/mama.shtml" target="_blank">准媽媽系列</a><br />
<a href="http://emag.yaolan.com/ezine/0-1.shtml" target="_blank">0-1系列</a><br />
<a href="http://emag.yaolan.com/ezine/1-3.shtml" target="_blank">1-3系列</a><br />
</div>
</li>
</ul>
</div>
</div>
<div id="append_parent"></div><div id="ajaxwaitid"></div>
<div class="wrap">
<div id="header">
<h2><div style="margin-top:15px"><a href="index.html" title="搖籃論壇"><img src="images/default/bbslogo.jpg" alt="搖籃論壇" border="0" /></a></div></h2>
<div id="ad_headerbanner"><iframe id="banner2" width="630" height="65" scrolling="no" frameborder="0" marginheight="0" marginwidth="0" class="left" src="http://adnet.yaolan.com/GetCommonAds.aspx?pos_id=321" ></iframe></div>
</div>
<div style="width:100%; height:30px; background-color:#FFBABC; " >
<form action="http://search.yaolan.com/luntan/ss.jsp" method="get" target="_blank">
<div style="width:205px; height:21px; margin:5px 0 0 15px; float:left;">
<select name="searchfw">
<option value="0" selected="selected">全部</option>
<option value="1">主題</option>
<option value="2">作者</option>
</select>
<input name="searchword" id="searchword" onmouseover="this.select();" onkeydown="checkKey(event, document.getElementById('lnkSearch'))" type="text" style="width:102px; " />
<input value="" type="Submit" class="dzwc_b1" />
</div>
<span style=" height:30px; line-height:30px; float:left;">
</span>
</form>
</div>
<style type="text/css">
.defaultpost { height: auto !important; height:120px; min-height:120px !important; }
</style>
<script src="include/javascript/viewthread.js" type="text/javascript"></script>
<script type="text/javascript">zoomstatus = parseInt(1);</script>
<div id="infosidemain">
<div id="foruminfo">
<div id="nav">
<div class="userinfolist">
<p style="font-size:14px;"><a href="index.html" id="forumlist" onmouseover="showMenu(this.id)" class="dropmenu">搖籃論壇</a> » <a href="board_24.aspx">女人心情</a> » 合租女孩洗澡不關門,用手機拍了幾張相片。。【好圖共賞】</p>
</div>
</div>
<div id="headsearch">
</div>
</div>
<div id="ad_text"></div>
<div class="pages_btns">
<div class="threadflow"><a href="redirect.php?fid=24&tid=51269126&goto=nextoldset"> ‹‹ 上一主題</a> | <a href="redirect.php?fid=24&tid=51269126&goto=nextnewset">下一主題 ››</a></div>
<div class="pages"><em>44</em><strong>1</strong><a href="thread_51269126_2.aspx" >2</a><a href="thread_51269126_2.aspx" class="next">››</a></div> <a href="#tobottom" style="float:right;margin:10px 0 0 10px; color:#666666; text-decoration:underline">到樓底</a>
<span class="postbtn" id="newspecial" onmouseover="$('newspecial').id = 'newspecialtmp';this.id = 'newspecial';showMenu(this.id)"><a target="_blank" href="post.php?action=newthread&fid=24&extra="><img src="images/default/newtopic.gif" border="0" alt="發新話題" title="發新話題" /></a></span>
<span class="replybtn"><a href="post.php?action=reply&fid=24&tid=51269126&extra="><img src="images/default/reply.gif" border="0" alt="" /></a></span></div>
<ul class="popupmenu_popup newspecialmenu" id="newspecial_menu" style="display: none">
<li><a target="_blank" href="post.php?action=newthread&fid=24&extra=">發新話題</a></li>
<li class="poll"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=1">發布投票</a></li> <li class="trade"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=2">發布商品</a></li> <li class="reward"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=3">發布懸賞</a></li> <li class="activity"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=4">發布活動</a></li> <li class="debate"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=5">發布辯論</a></li> <li class="video"><a target="_blank" href="post.php?action=newthread&fid=24&extra=&special=6">發布視頻</a></li> </ul>
<form method="post" name="modactions">
<input type="hidden" name="formhash" value="7150568c" />
<div class="mainbox viewthread " style=" background:url(images/default/bbs_bg7.gif) repeat-x top" >
<span class="headactions">
</span>
<h1><span class="kv_threadtitle">[主題]<a href="forumdisplay.php?fid=24&filter=type&typeid=48">[家長里短]</a> 合租女孩洗澡不關門,用手機拍了幾張相片。。【好圖共賞】</span>
</h1>
<table id="pid51598839" summary="pid51598839" cellspacing="0" cellpadding="0">
<tr>
<td class="postauthor">
<div class="online" >
<cite>
<a href="http://space.yaolan.com/50036303" target="_blank" id="userinfo51598839" class="dropmenu" onmouseover="showMenu(this.id)">狂戰</a>
<em>其它</em>
</cite>
</div>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" >
<b style="color:#009900;width:100px;display:block">新生搖精</b>
<a href="http://space.yaolan.com/50036303" target="_blank" >
<a border="0" target="_blank" href="http://space.yaolan.com/50036303"><img src="/uc/images/noavatar_middle.gif" onerror="this.onerror=null;this.src='/uc/images/noavatar_middle.gif'" width="90" height="90"></a>
</a>
<br/>
<a href="http://space.yaolan.com/50036303" target="_blank" border="0"><img src="/images/headpng/head_1_0_0.png" /></a>
<p style="text-align:center;"><a href="http://www.yaolan.com/help/article2007_462561627026.shtml" target="_blank" border="0"><font color="#ff6600" style="font-size:12px;" >新生搖精</font></a></p>
</td>
<td >
<a name="newpost"></a>
<!-- <p><img src="images/default/star_level1.gif" alt="Rank: 1" /></p>-->
<ul>
<li></li>
<li class="pm"><a href="http://my.yaolan.com/Message/NewWriteMessage.aspx?u=50036303" target="_blank">短消息</a></li>
<li class="buddy"><a href="http://space.yaolan.com/50036303/friends/addfriend.html" target="_blank">加好友</a></li>
<li class="space"><a href="http://space.yaolan.com/50036303/BBS" target="_blank">帖子集</a></li>
</ul>
<DIV style="margin:25px 0 0 5px;color:#999">活力: 192</DIV>
<DIV style="margin:0 0 0 5px;color:#999">魅力: 100</DIV>
<DIV style="margin:0 0 0 5px;color:#999">文采: 102</DIV>
</td>
</tr>
</table>
</td>
<td class="postcontent">
<div class="postinfo" style="background:#FFD8D9">
<strong>1<sup>#</sup></strong>
<em title="復制帖子鏈接到剪貼板" id="postnum51598839" onclick="set('http://bbs.yaolan.com/viewthread.php?tid=51269126&page=1#pid51598839', '帖子鏈接已經復制到剪貼板')"><a href="#">復制本樓地址</a></em>
<em><a href="viewthread.php?tid=51269126&page=1&authorid=50036303" rel="nofollow">只看該作者</a></em>
發表於 2009-3-16 14:40 瀏覽:532 回復:43
</div>
<div id="ad_thread2_0"></div> <div class="postmessage defaultpost" style="background:#FFFFFF">
<div id="ad_thread3_0"></div><div id="ad_thread4_0"></div>
<div id="postmessage_51598839" class="t_msgfont" style="padding:10px;"><img src="http://www.funbq.com/img/216/bq51551475.jpg" border="0" onclick="zoom(this, this.src)" onload="attachimg(this, 'load')" alt="" /><br />
一、此貼為調查貼,為配合公安部第二次全國色狼普查實名登記制,特發此貼,被標題吸引進入瀏覽的,不論男女,皆為色狼. <br />
<br />
二、帖子被瀏覽數即為色狼數量,統計結果截止到2009年8月31日. <br />
<br />
三、瀏覽此貼時,系統已自動記錄瀏覽者的ip地址以及論壇id,請勿抱有僥幸心理. <br />
<br />
四、不要說沒看清或點錯了之類的鬼話來為自己辯解 <br />
<br />
五、請於觀看此貼20日內與戶口所在地街道辦事處或派出所自帶小板凳聯系備案 <br />
<br />
六、此次調查結果將於2009年中在各地方電視台滾動播出,敬請期待。。。。。。。。<br />
<br />
[<i> 本帖最後由 狂戰 於 2009-3-16 15:17 編輯 </i>]</div>
㈣ EM演算法深度解析
最近在做文本挖掘的時候遇到了EM演算法,雖然讀書的時候簡單地接觸過,但當時並沒有深入地去了解,導致現在只記得演算法的名字。既然EM演算法被列為數據挖掘的十大演算法之一,正好借這個機會,重新學習一下這個經典的演算法。學習的過程中,我發現網上的資料大多講解地不夠細致,很多地方解釋得並不明了。因此我決定拋開別人的想法,僅從數學推導本身出發,盡力理解每一個公式的含義,並將其對應到實際的實驗過程當中。這篇博客記錄了我對與EM演算法的思考與理解,也是我人生中的第一篇博客,希望能夠對於想要學習EM演算法的同學有所幫助。
前面談到我在做文本挖掘的時候遇到了EM演算法,EM演算法用於估計模型中的參數。提到參數估計,最常見的方法莫過於極大似然估計——在所有的候選參數中,我們選擇的參數應該讓樣本出現的概率最大。相信看到這篇筆記的同學一定對極大似然估計非常熟悉,而EM演算法可以看作是極大似然估計的一個擴充,這里就讓我們用極大似然估計來解決一個簡單的例子,來開始正式的討論。
有A,B,C三枚硬幣,我們想要估計A,B,C三枚硬幣拋出正面的概率 , , 。我們按如下流程進行實驗100次:
記錄100次實驗的結果如下:
我們將上面的實驗結果表述如下:
表示第i次實驗中,硬幣A的結果,1代表正面,0代表反面; 表示第i次實驗中,硬幣B或硬幣C拋出正面的個數,則參數 的極大似然估計分別為:
即硬幣A,B,C各自拋出正面的次數占總次數的比例,其中 為指示函數。
實驗流程與1相同,但是我們不慎遺失了硬幣A的記錄結果,導致我們只知道隨後十次拋出了多少次正面,多少次反面,卻不知道實驗結果來自於硬幣B還是硬幣C。在這種情況下,我們是否還能估計出 , , 的值呢?
這時候利用極大似然估計似乎行不通了, 因為這種情況下,我們不但缺失了硬幣A產生的觀測值,同時也不知道哪些觀測值屬於硬幣B,哪些觀測值屬於硬幣C。
有些同學可能會提出,雖然我們無法得到三個硬幣各自產生的樣本,但是我們依然可以得到每個觀測值出現的概率。比如在第一次實驗中, 我們拋出了5次正面5次反面,我們可以做如下思考:
假設這5次正面由硬幣B得到,那麼概率應該為 ,而這次觀測值來自於硬幣B,也就是硬幣A拋出正面的概率為
假設這5次正面由硬幣C得到,那麼概率應該為 ,而這次觀測值來自於硬幣C,也就是硬幣A拋出反面的概率為
綜合起來,利用條件概率公式,這個觀測值出現的概率就是
因此我們可以將樣本整體的概率和似然函數利用 , , 表示出來,通過對似然函數求導,令其關於 的偏導數等於0,我們可以求出三個參數的值。
這個思路聽上去十分合理,我們可以順著這個思路進行數學推導,看看可以得到什麼樣的結果。首先我們計算樣本的概率:
對應的似然函數為
其中 關於 的條件分布為
的分布為
因此我們可以得到
至此,我們成功地得到了似然函數。然而觀察可以發現,這個函數是由100項對數函數相加組成,每個對數函數內部包含一個求和,想通過求導並解出導數的零點幾乎是不可能的。當然我們可以通過梯度下降來極小化這個函數,藉助深度學習庫的自動微分系統在實現上也非常容易。但是這種做法過於簡單粗暴,有沒有辦法來優雅地解決這個問題呢?在繼續討論之前,我們先將這類問題進行一般化表述:
我們觀測到隨機變數 產生的m個相互獨立的樣本 , 的分布由聯合分布 決定, 是缺失數據或無法在實驗中被直接觀測到,稱為 隱變數 ,我們想要從樣本中估計出模型參數 的值。在接下來的討論中,我們假定 的取值是離散的,於是可以得到似然函數如下:
接下來,我們就探討一下,如何利用EM演算法解決這個問題。
這一部分的數學推導,主要參考了吳恩達CS229n的筆記,並且根據個人的思考和理解,盡力對公式的每一步進行詳細的解釋。我們先簡單地介紹一下琴生不等式。
琴生不等式有多種形式,下面給出其離散形式的表述和概率論中的表述:
1.若 為嚴格凹函數, 為定義域內的n個點, 是n個正實數,且滿足 , 則下述不等式成立:
當且僅當 時,不等式取等號。
2.若 為嚴格凹函數, 為實值隨機變數,且期望存在,則下述不等式成立:
當且僅當 ,即 為常數時,不等式取等號。
註: 這里將函數上方為凹集的函數稱為凹函數, 例如 函數就是凹函數。
相信大家對琴生不等式都十分熟悉,因此這里就不做過多的說明。接下來,我們將琴生不等式應用到我們的問題中。
回到我們之前的問題上, 我們想要極大化下面這個函數:
但是我們無法對這個函數直接求導,因此我們藉助琴生不等式,對這個函數進行變換。為了讓過程看上去簡潔,下面只對求和中的第 項進行計算。
令 滿足 ,且 ,則根據琴生不等式,可以得到:
當且僅當 為常數時,上述不等式取等號。也就是說,對於任意 , 是一個與 無關的量。設對於任意 ,我們可以得到:
因此當 時,不等式 取等號,容易驗證此時 , 與 無關。將 綜合一下,我們可以得到以下結論:
到這里為止,我們已經擁有了推導出EM演算法的全部數學基礎,基於 我們可以構建出E步和M步。上面的數學推導雖然看上去略為復雜,但實際上只用到了三個知識點:
1.琴生不等式:
2.條件概率:
3.聯合分布求和等於邊緣分布:
對上面的數學推導有疑問的同學,可以結合上面這三點,再將整個推導過程耐心地看一遍。
大部分關於EM演算法的資料,只是在數學形式上引入了 函數,即 ,以滿足琴生不等式的使用條件,卻沒有過多地解釋 函數本身。這導致了很多人完全看懂了演算法的推導,卻還是不理解這些數學公式究竟在做什麼,甚至不明白EM演算法為什麼叫做EM演算法。所以在給出E步和M步之前,我想先談一談 函數。
我們回顧一下 函數所滿足的條件(暫時不考慮琴生不等式取等號的限制),
在 所有可能的取值處有定義。可以看出, 是 的樣本空間上任意的一個概率分布。因此,我們可以對不等式 進行改寫。首先我們可以將含有 的求和寫成期望的形式:
這里 指的是在概率分布 下,求隨機變數 和 的期望。有同學會問,為什麼我們平時求期望的時候只要寫 ,並沒有指明是在哪個概率分布下的期望。這是因為一般情況下,我們都清楚地知道隨機變數 所服從的分布 ,並且默認在分布 下求期望。
舉個例子,我手上有一個硬幣,拋了10次,問拋出正面次數的期望。這種情況下,大部分人會默認硬幣是均勻的,也就是說拋出正面的次數 服從二項分布 ,期望 。這時有人提出了質疑,他說我認為你這個硬幣有問題,拋出正面的概率只有0.3,那麼在他眼裡, 期望 。
回到正題,我們利用等式 改寫不等式 ,可以得到:
這正是琴生不等式在概率論中的形式。我們可以將不等式倒過來理解:
首先,假定隨機變數 服從概率分布 , 是 的樣本空間上的任意一個概率分布。這里 可以是一組定值,也可以是關於參數 的函數。
顯然,當我們取不同的 時,隨機變數 的期望也會隨之改變。需要注意的是,由於 與 相關,所以這里的期望不是一個數值,而是關於 的函數。
當我們令 為 的後驗分布 時,上面的期望最大。這里有兩點需要注意,1. 後驗分布 也是一個關於參數 的函數。2. 由於期望是關於 的函數,所以這里的最大指的並非是最大值,而是最大的函數。
若對於每一個 ,我們都令 為 的後驗分布 ,則上述期望之和等於我們要極大化的似然函數,即
通過上述分析,我們為尋找似然函數的極大值點 提供了一個思路。我們不去極大化似然函數本身,而是去極大化 。至於如何將這個思路實際應用,就要利用到EM演算法中的E-step和M-step。
這一節中,我們先給出E-step和M-step的數學形式,隨後在結合拋硬幣的例子來解釋這兩步究竟在做什麼。下面進入演算法的流程,首先我們任意初始化 ,按下述過程進行迭代直至收斂:
在第 次迭代中,
(E-step)對於每個 ,令
(M-step)更新 的估計值,令
EM演算法從任意一點 出發,依次利用E-step優化 ,M-step優化 ,重復上述過程從而逐漸逼近極大值點。而這個過程究竟是怎樣的呢,就讓我們一步步地揭開EM演算法的面紗。
假設我們現在隨機初始化了 ,進入第一輪迭代:
(E-step)
由於我們已經假定模型參數為 ,所以此時 不再是與 有關的函數,而是由一組常數構成的概率分布。結合拋硬幣的例子來看,這一步是在我們已知模型參數 的基礎上(雖然這是我們瞎猜的),去推測每一次的觀測值是由哪個硬幣產生的,或者說我們對每一次觀測值做一個軟分類。比如我們根據初始化的參數,計算出 , 。可以解釋為第 個觀測值有20%的概率來自於硬幣B,80%的概率來自於硬幣C;或者說硬幣A拋出了0.2個正面,0.8個反面。
(M-step)
考慮到 是一組常數,我們可以舍棄常數項,進一步簡化上面這個要極大化的函數
由於 不再與 相關,因此上面的函數變成了對數函數求和的形式,這個函數通常來說是容易求導的,令導數等於0,我們可以求出新的參數 。我們仍舊以拋硬幣為例進行解釋,
令 , 可以得到,
這三個參數的解釋是顯而易見的。我們在E-step中對每個觀測值進行了軟分類, 可以看成是硬幣A拋出正面的次數,所以 是 的極大似然估計; 是我們拋硬幣B的次數, 是硬幣B拋出正面的次數,所以 是 的極大似然估計;對於 我們有相同的解釋。
我們將這個結果與拋硬幣1中極大似然估計的結果相比較可以發現,之前結果中的指示函數 變成了這里的 ,在指示函數下,某個觀測值要麼來自於硬幣B,要麼來自於硬幣C,因此也稱為硬分類。而在 函數下,某個觀測值可以一部分來自於硬幣B,一部分來自於硬幣C,因此也稱作軟分類。
將上述兩步綜合起來,EM演算法可以總結如下:我們首先初始化模型的參數,我們基於這個參數對每一個隱變數進行分類,此時相當於我們觀測到了隱變數。有了隱變數的觀測值之後,原來含有隱變數的模型變成了不含隱變數的模型,因此我們可以直接使用極大似然估計來更新模型的參數,再基於新的參數開始新一輪的迭代,直到參數收斂。接來下我們就討論為什麼參數一定會收斂。
前面寫了太多的公式,但是這一部分我不打算給出收斂性的數學推導。其實數學上證明EM演算法的收斂性很容易,只需要證明每一輪迭代之後,參數的似然函數遞增,即