文本分類學習 (五) 機器學習SVM的前奏-特徵提取(卡方檢驗續集)

前言:

上一篇比較詳細的介紹了卡方檢驗和卡方分佈。這篇咱們就實際操刀,找到一些訓練集,正所謂紙上得來終覺淺,絕知此事要躬行。然而我在躬行的時候,發現了卡方檢驗對於文本分類來講應該把公式再變形通常,那樣就完美了。php

目錄:

一,回顧卡方檢驗

1.公式一:

先回顧一下卡方檢驗:html

卡方檢驗:事先作一個假設,計算由有假設得來的理論值於實際觀察值之間的誤差來推斷這個假設是否成立,公式:java

2.四表格的卡方檢驗公式:

卡方檢驗對於文本分類:每一個詞對於每一個類別,使用四表格的形式,計算該詞對於該類是否有較大的影響,公式:web

 

二,訓練集的準備

我選擇了復旦語料庫中的歷史篇:469篇正則表達式

每篇的格式大多以下:redis

【 文獻號 】1-1408
【原文出處】科技日報
【原刊地名】京
【原刊期號】19960825
【原刊頁號】⑵
【分 類 號】K91
【分 類 名】中國地理
【 做  者 】於希賢
【複印期號】199610
【 標  題 】歷史上中國地理環境的幾回突變
【 正  文 】
    在人類歷史時期,特別是有文字記載的近幾千年來地理環境有沒有變化?有多大變化?是怎樣變化的?這是人們廣泛關心的問題,也是學
術界長期爭論不休的問題之一。
    以氣候而言,古代歐洲亞里士多德相信寒冷而多雨的氣候是週期循環的。此後19世紀至20世紀初,德國的漢恩和法國的阿拉哥爲表明
,倡導氣候不變論。直至本世紀70年代,把地理環境的變化僅誤認爲是一種單純的「緩慢的漸進做用」。甚至認爲不因人的活動,天然環境
的變化是很是微小的。
    事實上,有史時代人類生活的地理環境,不只有其相對緩慢變化的平靜時期,也有其激烈動盪的突變時期。
    地理環境中天然災異的羣發性和集中突發性造成了地理環境的突變。如火山噴發、地震山崩、海浸海退、大雨洪水、江河氾濫、乾旱螟蝗
、瘟疫肆虐、大雪奇寒、生物彙集、變遷和大規模遷徙,奇特的天文現象(太陽黑子、流星雨等),這樣一些災異在近幾千年來有時出現多而
集中,這就是突變期;有時出現少而分散,這是漸變期。
    根據歷史文獻記載和考古及歷史地理野外調查,初步至少提出如下一些災變期。
    大約距今4000年先後有洪水災變期。
    在中國、歐洲和中近東的許多民族如巴比倫、波斯、印度等都普遍地有洪水災變的記載和傳說。《尚書·堯典》首記其事「湯湯懷山襄陵
,浩浩滔天」。《孟子·滕文公》說:「昔堯之時,天下猶未平,洪水橫流,氾濫於天下……」。當今的考古發掘與上述記述相吻合。距今4
000年先後,黃河下游曾大改道。洪水發生的地域正是《禹貢》九州中的兗州、豫州和徐州。考古學家俞偉超教授研究說:中國北方的龍山
文化和江浙一帶的良渚文化一度都達到了至關高度的文明。「距今4000年之時,狀況突然大變。龍山文化變爲嶽石文化,良渚文化也忽然
變爲馬橋、湖熟文化。……時代雖然先後相接、文化面貌卻缺少緊密的承襲關係。……嶽石與馬橋、湖熟諸文化遺址分佈密度、居址的面積、
乃至文化自己的產生、生活水平,又皆遠遠低於龍山、良渚文化」。他指出「這是由於生產、生活環境發生了巨大變化,族羣人口大爲減小,
文化處於低落時期的遺存。」據此,他推斷說:「4000多年之前我國曾發生一次延續若干年的洪水大災難,應該是歷史事實。」
    距今2100多年前,我國逐步進入另外一次災變時期,其高潮是公元2年至57年間。
    西漢末年曾發生了渤海海灣西岸大海浸。《漢書·溝洫志》記載「河入勃海……海水溢西南出,浸九百里,九河之地已爲東海所漸矣」。
宋代的學者認爲自碣石以西現今整個勃海灣在此以前全是陸地。譚其驤教授研究認爲「其海浸範圍當今渤海灣4米等高線如下」。今天津、黃
驊、寧海一帶有幾十處文化遺址,它們不是東周、西漢時期,就是隋唐時期。其間獨缺失東漢魏晉南北朝時期的文化遺址。筆者在武清縣雍奴
故城遺址上發現海相地層。在西漢泉州故城遺址上已湮沒2米深淤泥。當時確有大海浸。海浸以前的許多村落、城市被海相地層壓置。至公元
6世紀海水退出,又纔有新的村落與文化層。當中獨缺失公元1—5世紀的人類活動痕跡。
    《漢書·五行志》載,「漢成帝和平元年(前28)三月己未(14日)日出黃,有黑氣大如錢,居日中央」,這條記載是世界上公認的
太陽黑子活動的最先記錄。此黑子之大,爲後世罕見。
    公元11年黃河在今河北大名決口氾濫,禍及河東數郡。此次水災延續了60年。至公元70年才由王景領導的數十萬民工治好。據鄧雲
特統計,這57年中共發生9次特大蝗災,8次特大水災,3次特大瘟疾,導致「死者十之七八」。公元2年全國人口5900多萬,至公元
57年全國人口僅有2100多萬,減小了3800多萬。
    公元9—12世紀的寒冷災變期。
    赫連勃勃的夏國首都統萬城(今陝西橫山西北)原先是一片「臨廣澤而帶清流」的美麗城市。至公元882年已「堆沙高及城堞」。又過
100年已「深在沙漠」之中了。公元925年兩漢大水,戶口流亡者十之四五。938年定州大旱民多流散。943年春夏旱,秋冬水。蝗
大起,東自海濱,西抵隴坻,南逾江淮,北至幽冀,原野山谷,城郭廬舍皆滿,竹木俱盡,……民餒者數十萬口,流亡不計其數。朱熹統計,
有史以來黃河大決16次,其中五代半個世紀內,就佔了9次,至北宋尤甚。
    16—17世紀寒冷災變期。
    長白山主峯白頭山兩次噴發過。黑龍江德都火山1720年先後也噴發過。雲南騰衝打鷹山在1611年先後也噴發過。公元1555年
陝西、山西、河南同時大地震。此期水災、旱災不少,尤以大雪奇寒爲甚。1616年黃山連續積雪達130多天,河南嵩山1623年「雪
深道絕」。太華山泓谷至陰曆三月初三還「層冰積雪,狀滿谷間」。1628年福建順昌於陰曆三月十九還「羣峯積雪,有如環玉」。163
3年陰曆八月初六日五臺山仍「滴水皆冰」「陰崖懸冰數百丈」。依據種種資料證明,此冷期「擺動範圍」遠比竺可楨肯定的±℃爲大,冬
半年當較今冷6—℃左右。
    明末災異的羣發性與突發性,使當時官員金士衡在「邸報」中總結說:「舉報重極大之災,至怪至異之事,畢集於一時」。
    總之,從有史時代地理環境幾千年的變異來看,一方面要正視地理環境的突變,災異羣的出現會給人類社會形成明顯甚至是重大的影響。
地理環境的變化參與了人類歷史發展演化的進程。另外一方面也應當看到地理環境幾千年來的災變,並無形成「世界末日」。科學的態度是從
查清歷史事實中,令人們有一個清醒的認識和恰當的選取對策。
    (做者系北京大學地理系教授、中國地理學會歷史地理專業委員會副主任)*
    
    
    
 
歷史類文檔

本身爬了博客園的博客:420篇算法

選擇一篇貼出來:數據庫

Redis特性和應用場景
Redis特性 速度快 Redis使用標準C編寫實現,並且將全部數據加載到內存中,因此速度很是快。官方提供的數據代表,在一個普通的Linux機器上,Redis讀寫速度分別達到81000/s和110000/s。 數據結構 能夠將Redis看作「數據結構服務器」。目前,Redis支持5種數據結構。 持久化 因爲全部數據保持在內存中,因此對數據的更新將異步地保存到磁盤上,Redis提供了一些策略來保存數據,好比根據時間或更新次數。數據超過內存,使用swap,保證數據; memcacache不能持久化,mongo是部分在內存; 自動操做 Redis對不一樣數據類型的操做是自動的,所以設置或增長key值,從一個集合中增長或刪除一個元素都能安全的操做。 支持多種語言 Redis支持多種語言,諸如Ruby,Python, Twisted Python, PHP, Erlang, Tcl, Perl, Lua, Java, Scala, Clojure等。 主-從複製 Redis支持簡單而快速的主-從複製。 官方提供了一個數據,Slave在21秒即完成了對Amazon網站10Gkey set的複製。 Sharding 很容易將數據分佈到多個Redis實例中,但這主要看該語言是否支持。目前支持Sharding功能的語言只有PHP、Ruby和Scala。 1.   redis數據使用方式 redis 的做者antirez曾笑稱其爲一個數據結構服務器(data structures server),redis的全部功能就是將數據以其固有的幾種結構保存,並提供給用戶操做這幾種結構的接口。咱們能夠想象咱們在各類語言中的那些固有數據類型及其操做。 Redis的幾種使用方式  Strings Hashs Lists Sets Sorted Sets Pub/Sub  Redis的七種特性以及適合的應用場景: 1.1. Strings Strings 數據結構是簡單的key-value類型,value其實不只是String,也能夠是數字。使用Strings類型,徹底實現目前 Memcached 的功能,而且效率更高。還能夠享受Redis的定時持久化,操做日誌及 Replication等功能。除了提供與 Memcached 同樣的get、set、incr、decr 等操做外,Redis還提供了下面一些操做:  獲取字符串長度           strlen 往字符串append內容 append 設置和獲取字符串的某一段內容 setrange getrange 設置及獲取字符串的某一位getrange 批量設置一系列字符串的內容  String是最簡單的數據類型,一個key對應一個Value,String是二進制安全的。它能夠包含任何數據,圖片或者其餘序列化後的對象     方法   說明   特性     set   設置key對應的的值爲String類型的value           get   獲取對應key對應的String的值,若是不存在返回nil           setnx   設置能夠爲對應的值爲String類型的value,若是key存在返回0不覆蓋,不存在返回1   nx的意思爲not exist Set the value of a key, only if the key does not exist     setex   置key對應的值爲String類型的value,並指定此鍵值對應的有效期 SETEX key seconds value   例:setex mykey 10 你好     setrange   設置key的value的子字符串   setrange key 位置 替換的內容 若是替換內容沒有原value長,則原value剩餘的內容將被保留     mset   一次設置多個key的值,成功返回ok,失敗返回0,要成功都成功,要不成功所有失敗。   mset key1 內容一 key2 內容二     msetnx   一次設置多個key的值,成功返回ok,失敗返回0,不覆蓋已經存在的值,要成功都成功,要失敗都失敗。           getset   設置key的值並返回key的舊值   getset key newValuse     getrange   獲取key對應的value子字符串   getrange key 0 5 //獲取前6個字符     mget   批量獲取   mget key1 key2 key3 //沒有設置則返回空     incr   對key的值作增長操做,並返回新的值      +1     incrby   對能夠的value加指定的值,   key若是不存在會設置key並value爲0 incrby key1 5 //對key1的值加5     decr   對key的值作減減操做       -1     decrby   對key的值減去指定值           append   給指定key的字符串追加value,返回新的字符串長度           strlen   取指定key的value值的長度           1.2. Hashs 在Memcached中,咱們常常將一些結構化的信息打包成hashmap,在客戶端序列化後存儲爲一個字符串的值,好比用戶的暱稱、年齡、性別、積分等,這時候在須要修改其中某一項時,一般須要將全部值取出反序列化後,修改某一項的值,再序列化存儲回去。這樣不只增大了開銷,也不適用於一些可能併發操做的場合(好比兩個併發的操做都須要修改積分)。而Redis的Hash結構能夠使你像在數據庫中Update一個屬性同樣只修改某一項屬性值。   它是一個String類型的field和value的映射表,它的添加和刪除都是平均的,hash特別適合用於存儲對象,對於將對象存儲成字符串而言,hash會佔用更少的內存,而且能夠更方便的存取整個對象. 它和java的HashMap徹底相似     方法   說明   特性     hset   設置一個hash 的field爲指定值,若是key不存在則先建立   hset tab ke1 val1     hget   獲取某個hash的某個field值   hget tab ke1     hsetnx   相似string只是操做的是hash           hmset   批量設置hash的內容           hmget   獲取hash表的所有key值   Hmget key field1 field2     hincrby   給hash表的某個字段增長值           hexists   判斷hash表中某個key是否存在           hlen   返回hash表中的key數量           hdel   刪除指定hash表的某個鍵值對           hkeys   返回hash表中全部的key            hvals   返回hash表中全部的value           hgetall    獲取hash表中全部key和value           1.3. Lists Lists 就是鏈表,略有數據結構知識的人都應該能理解其結構。使用Lists結構,咱們能夠輕鬆地實現最新消息排行等功能。Lists的另外一個應用就是消息隊列,能夠利用Lists的PUSH操做,將任務存在Lists中,而後工做線程再用POP操做將任務取出進行執行。Redis還提供了操做Lists中某一段的api,你能夠直接查詢,刪除Lists中某一段的元素。 Redis的list是每一個子元素都是String類型的雙向鏈表,能夠經過push和pop操做從列表的頭部或者尾部添加或者刪除元素,這樣List便可以做爲棧,也能夠做爲隊列。         方法   說明   特性     lpush   在key所對應的list頭部添加一個元素   l的意思是left     rpush   在key說對應的list尾部添加一個元素   r的意思是right     lrange   顯示list裏面的內容   lrange 0 -1 //所有顯示     linsert   在key對應的list   linsert mylist before one myvalue     lset   設置list中指定下標元素的值   lset mylist index myvalue     lrem   從key對應的list中刪除n個和value相同的元素,結果返回影響元素的個數,n<0從尾部開始刪除,n=0全刪除   lrem mylist count "value"     ltrim   保留指定key範圍內的數據,返回ok成功   ltrim mylist 0 3 //0-3是保留的範圍     lpop   從list的頭部刪除一個元素,並返回該刪除的元素         rpop   從list的尾部彈出一個元素,並返回該刪除的元素         rpoplpush   從第一個list的尾部元素異常元素並添加到第二個list的頭部   rpoplpush mylistA mylistB     lindex   返回list位置的元素   lindex mylist 3     llen   返回list中元素的個數   llen mylist     1.4. Sets Sets 就是一個集合,集合的概念就是一堆不重複值的組合。利用Redis提供的Sets數據結構,能夠存儲一些集合性的數據。 案例: 在微博應用中,能夠將一個用戶全部的關注人存在一個集合中,將其全部粉絲存在一個集合。Redis還爲集合提供了求交集、並集、差集等操做,能夠很是方便的實現如共同關注、共同喜愛、二度好友等功能,對上面的全部集合操做,你還能夠使用不一樣的命令選擇將結果返回給客戶端仍是存集到一個新的集合中。 Set是集合,是String類型的無序集合,set是經過hashtable實現的,概念和數學中個的集合基本相似,能夠交集,並集,差集等等,set中的元素是沒有順序的。     方法   說明   特性     sadd   向名稱爲key的set中添加元素,返回影響元素的個數,0爲失敗,1爲成功   sadd myset value     smembers   查看集合中全部的成員   smebers myset     srem   刪除集合的一個元素   srem myset two     spop   隨機返回並刪除set中一個元素   spop myset     sdiff   返回全部set與第一個set的差集   sdiff myset1 myset2     sdiffstore   比較差集而且存儲到另外一個set中,返回1表明成功   sdiffstore setstoreSet mySet1 myset2     sinter   返回全部給定集合的交集   sinter myset1 mysert2 //1集合和2集合的交集     sinterstore   返回給定集合的交集並存儲到另外一個集合   sinterstore desset myset1 myset2 //存到desset集合中     sunion   返回全部給定集合的並集   sunion set1 set2     sunionstore   返回全部的並集而且存儲到另外一個集合中,返回影響的元素個數   sunionstore destSet myset1 myset2     smove   把第一個集合的元素移動到第二個集合中   smove myset myset 你好     scard   返回集合中元素的個數   scard myset1     sismember   測試某個元素是否在集合中,返回0是否是,大於0是存在   sismember mykey1 你好     srandmember   隨機返回個集合中的元素   srandmemeber myset1     1.5. Sorted Sets 和Sets相比,Sorted Sets增長了一個權重參數score,使得集合中的元素可以按score進行有序排列,好比一個存儲全班同窗成績的Sorted Sets,其集合value能夠是同窗的學號,而score就能夠是其考試得分,這樣在數據插入集合的時候,就已經進行了自然的排序。 案例: 能夠用Sorted Sets來作帶權重的隊列,好比普通消息的score爲1,重要消息的score爲2,而後工做線程能夠選擇按score的倒序來獲取工做任務。讓重要的任務優先執行。   Zset類型 它是set的一個升級版本,在set的基礎上增長了順序,這一屬性在添加修改元素時能夠指定,每次指定後,zset會自動按新的值調整順序。     方法   說明   特性     zadd   向zset中添加元素member,score 用於排序,若是元素存在,則更新其順序,返回0表明沒添加成功   ZADD key score member zadd myset 3 itim     zrange   取出集合中的元素   zrange myset 0 -1 withscores//顯示序號 by index     zrem   刪除名稱爲key的zset中的元素member   zrem myset itim     zincrby   修改元素的排序,若是元素不存在則添加該元素,且排序的score值爲增長值   zincrby myzset score itim     zrank   返回元素在集合中的排序位置,就是索引值   zrank myzset itim //itim在集合中的位置     zrevrank   返回從大到小的排序索引值,就是逆序位置   zrevrangk myzset itim//逆序的位置     zrevrange   返回集合中從大到小排序(降序)的,索引start到end的全部元素   zrevrange myzset 0 -1 //逆序後的元素     zrangebyscore   根據排序索引的scores來返回元素   zrangebyscore myzset 1 3 withscores//     zcount   返回集合中給定區間的數量   zcount myzset 2 4 //集合中2-4索引元素的個數     zcard   返回集合中全部元素的個數   zcard myzset //返回全部元素的個數     zremrangebyrank   刪除集合中排序在給定區間的全部元素(按索引刪除)   zremrangebyrank myzset 2 3 //     zremrangebyscore   刪除集合中在給定排序區間的元素 (按順序刪除)   zremrangebyscore myzset 2 5 //     1.6. Pub/Sub Pub/Sub 從字面上理解就是發佈(Publish)與訂閱(Subscribe),在Redis中,你能夠設定對某一個key值進行消息發佈及消息訂閱,當一個key值上進行了消息發佈後,全部訂閱它的客戶端都會收到相應的消息。這一功能最明顯的用法就是用做實時消息系統,好比普通的即時聊天,羣聊等功能。 案例: Qlocenter 下發策略 2.   redis數據存儲 redis的存儲分爲內存存儲、磁盤存儲和log文件三部分,配置文件中有三個參數對其進行配置。 l save seconds updates save配置,指出在多長時間內,有多少次更新操做,就將數據同步到數據文件。這個能夠多個條件配合,好比默認配置文件中的設置,就設置了三個條件。   l appendonly yes/no appendonly配置,指出是否在每次更新操做後進行日誌記錄,若是不開啓,可能會在斷電時致使一段時間內的數據丟失。由於redis自己同步數據文件是按上面的save條件來同步的,因此有的數據會在一段時間內只存在於內存中。   l appendfsync no/always/everysec appendfsync配置,no表示等操做系統進行數據緩存同步到磁盤,always表示每次更新操做後手動調用fsync()將數據寫到磁盤,everysec表示每秒同步一次。   redis使用了兩種文件格式:全量數據和增量請求。 全量數據格式是把內存中的數據寫入磁盤,便於下次讀取文件進行加載; 增量請求文件則是把內存中的數據序列化爲操做請求,用於讀取文件進行replay獲得數據,序列化的操做包括SET、RPUSH、SADD、ZADD。 redis是一個支持持久化的內存數據庫,也就是說redis須要常常將內存中的數據同步到磁盤來保證持久化。redis支持兩種持久化方式,一種是 Snapshotting(快照)也是默認方式,另外一種是Append-only file(縮寫aof)的方式。下面分別介紹Snapshotting(RDB方式)     快照是默認的持久化方式。這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名爲dump.rdb。能夠經過配置設置自動作快照持久 化的方式。咱們能夠配置redis在n秒內若是超過m個key被修改就自動作快照,下面是默認的快照保存配置save 900 1 #900秒內若是超過1個key被修改,則發起快照保存save 300 10 #300秒內容如超過10個key被修改,則發起快照保存save 60 10000下面介紹詳細的快照保存過程1.redis調用fork,如今有了子進程和父進程。2. 父進程繼續處理client請求,子進程負責將內存內容寫入到臨時文件。因爲os的寫時複製機制(copy on write)父子進程會共享相同的物理頁面,當父進程處理寫請求時os會爲父進程要修改的頁面建立副本,而不是寫共享的頁面。因此子進程的地址空間內的數 據是fork時刻整個數據庫的一個快照。3.當子進程將快照寫入臨時文件完畢後,用臨時文件替換原來的快照文件,而後子進程退出。client 也能夠使用save或者bgsave命令通知redis作一次快照持久化。save操做是在主線程中保存快照的,因爲redis是用一個主線程來處理全部 client的請求,這種方式會阻塞全部client請求。因此不推薦使用。另外一點須要注意的是,每次快照持久化都是將內存數據完整寫入到磁盤一次,並不 是增量的只同步髒數據。若是數據量大的話,並且寫操做比較多,必然會引發大量的磁盤io操做,可能會嚴重影響性能。另外因爲快照方式是在必定間隔時間作一次的,因此若是redis意外down掉的話,就會丟失最後一次快照後的全部修改。若是應用要求不能丟失任何修改的話,能夠採用aof持久化方式。下面介紹Append-only file(AOF方式)    aof 比快照方式有更好的持久化性,是因爲在使用aof持久化方式時,redis會將每個收到的寫命令都經過write函數追加到文件中(默認是 appendonly.aof)。當redis重啓時會經過從新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。固然因爲os會在內核中緩存 write作的修改,因此可能不是當即寫到磁盤上。這樣aof方式的持久化也仍是有可能會丟失部分修改。不過咱們能夠經過配置文件告訴redis咱們想要 經過fsync函數強制os寫入到磁盤的時機。有三種方式以下(默認是:每秒fsync一次)appendonly yes              //啓用aof持久化方式# appendfsync always      //每次收到寫命令就當即強制寫入磁盤,最慢的,可是保證徹底的持久化,不推薦使用appendfsync everysec     //每秒鐘強制寫入磁盤一次,在性能和持久化方面作了很好的折中,推薦# appendfsync no         //徹底依賴os,性能最好,持久化沒保證aof 的方式也同時帶來了另外一個問題。持久化文件會變的愈來愈大。例如咱們調用incr test命令100次,文件中必須保存所有的100條命令,其實有99條都是多餘的。由於要恢復數據庫的狀態其實文件中保存一條set test 100就夠了。爲了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照相似的方式將內存中的數據 以命令的方式保存到臨時文件中,最後替換原來的文件。具體過程以下1. redis調用fork ,如今有父子兩個進程2. 子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令3. 父進程繼續處理client請求,除了把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就能保證若是子進程重寫失敗的話並不會出問題。4. 當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程。而後父進程把緩存的寫命令也寫入到臨時文件。5. 如今父進程能夠使用臨時文件替換老的aof文件,並重命名,後面收到的寫命令也開始往新的aof文件中追加。 須要注意到是重寫aof文件的操做,並無讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點相似。 3.   主從複製 redis主從複製配置和使用都很是簡單。 經過主從複製能夠容許多個slave server擁有和master server相同的數據庫副本。下面是關於redis主從複製的一些特色 l master能夠有多個slave l 除了多個slave連到相同的master外,slave也能夠鏈接其餘slave造成圖狀結構 l 主從複製不會阻塞master。也就是說當一個或多個slave與master進行初次同步數據時,master能夠繼續處理client發來的請求。相反slave在初次同步數據時則會阻塞不能處理client的請求。 l 主從複製能夠用來提升系統的可伸縮性,咱們能夠用多個slave 專門用於client的讀請求,好比sort操做能夠使用slave來處理。也能夠用來作簡單的數據冗餘 l 能夠在master禁用數據持久化,只須要註釋掉master 配置文件中的全部save配置,而後只在slave上配置數據持久化。 主從複製的過程    當設置好slave服務器後,slave會創建和master的鏈接,而後發送sync命令。不管是第一次同步創建的鏈接仍是鏈接斷開後的從新連 接,master都會啓動一個後臺進程,將數據庫快照保存到文件中,同時master主進程會開始收集新的寫命令並緩存起來。後臺進程完成寫文件後,master就發送文件給slave,slave將文件保存到磁盤上,而後加載到內存恢復數據庫快照到slave上。接着master就會把緩存的命 令轉發給slave。並且後續master收到的寫命令都會經過開始創建的鏈接發送給slave。從master到slave的同步數據的命令和從 client發送的命令使用相同的協議格式。當master和slave的鏈接斷開時slave能夠自動從新創建鏈接。若是master同時收到多個 slave發來的同步鏈接命令,只會使用啓動一個進程來寫數據庫鏡像,而後發送給全部slave。 4.   Redis應用場景 毫無疑問,Redis開創了一種新的數據存儲思路,使用Redis,咱們不用在面對功能單調的數據庫時,把精力放在如何把大象放進冰箱這樣的問題上,而是利用Redis靈活多變的數據結構和數據操做,爲不一樣的大象構建不一樣的冰箱。 Redis比較適合的一些應用場景,NoSQLFan簡單列舉在這裏,供你們一覽: 1.7.1.取最新N個數據的操做 記錄前N個最新登錄的用戶Id列表,超出的範圍能夠從數據庫中得到。 //把當前登陸人添加到鏈表裏 ret = r.lpush("login:last_login_times", uid) //保持鏈表只有N位 ret = redis.ltrim("login:last_login_times", 0, N-1) //得到前N個最新登錄的用戶Id列表 last_login_list = r.lrange("login:last_login_times", 0, N-1)   好比sina微博: 在Redis中咱們的最新微博ID使用了常駐緩存,這是一直更新的。可是咱們作了限制不能超過5000個ID,所以咱們的獲取ID函數會一直詢問Redis。只有在start/count參數超出了這個範圍的時候,才須要去訪問數據庫。 咱們的系統不會像傳統方式那樣「刷新」緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其餘類型數據庫)只是在用戶須要獲取「很遠」的數據時纔會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。   1.7.2.排行榜應用,取TOP N操做 這個需求與上面需求的不一樣之處在於,前面操做以時間爲權重,這個是以某個條件爲權重,好比按頂的次數排序,這時候就須要咱們的sorted set出馬了,將你要排序的值設置成sorted set的score,將具體的數據設置成相應的value,每次只須要執行一條ZADD命令便可。 //將登陸次數和用戶統一存儲在一個sorted set裏 zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3 ZADD key score member //當用戶登陸時,對該用戶的登陸次數自增1 ret = r.zincrby("login:login_times", 1, uid) //那麼如何得到登陸次數最多的用戶呢,逆序排列取得排名前N的用戶 ret = r.zrevrange("login:login_times", 0, N-1) ZREVRANGE key start stop [WITHSCORES] 另外一個很廣泛的需求是各類數據庫的數據並不是存儲在內存中,所以在按得分排序以及實時更新這些幾乎每秒鐘都須要更新的功能上數據庫的性能不夠理想。        典型的好比那些在線遊戲的排行榜,好比一個Facebook的遊戲,根據得分你一般想要:          - 列出前100名高分選手          - 列出某用戶當前的全球排名     這些操做對於Redis來講小菜一碟,即便你有幾百萬個用戶,每分鐘都會有幾百萬個新的得分。     模式是這樣的,每次得到新得分時,咱們用這樣的代碼:     ZADD leaderboard <score> <username>     你可能用userID來取代username,這取決於你是怎麼設計的。     獲得前100名高分用戶很簡單:ZREVRANGE leaderboard 0 99。 用戶的全球排名也類似,只須要:ZRANK leaderboard <username>。 ZRANK key member Determine the index of a member in a sorted set 1.7.3.須要精準設定過時時間的應用 好比你能夠把上面說到的sorted set的score值設置成過時時間的時間戳,那麼就能夠簡單地經過過時時間排序,定時清除過時數據了,不只是清除Redis中的過時數據,你徹底能夠把Redis裏這個過時時間當成是對數據庫中數據的索引,用Redis來找出哪些數據須要過時刪除,而後再精準地從數據庫中刪除相應的記錄。 1.7.4.獲取某段時間全部數據去重值 這個使用Redis的set數據結構最合適了,只須要不斷地將數據往set中扔就好了,set意爲集合,因此會自動排重。 1.7.5.Pub/Sub構建實時消息系統 Redis的Pub/Sub系統能夠構建實時的消息系統 好比不少用Pub/Sub構建的實時聊天系統的例子。 1.7.6.消息隊列系統 使用list能夠構建隊列系統,使用sorted set甚至能夠構建有優先級的隊列系統。 好比:將Redis用做日誌收集器 實際上仍是一個隊列,多個端點將日誌信息寫入Redis,而後一個worker統一將全部日誌寫到磁盤。 1.7.7.      緩存 性能優於Memcached,數據結構更多樣化。 1.7.8.範圍查找 好比:有一個IP範圍對應地址的列表,如今須要給出一個IP的狀況下,迅速的查找到這個IP在哪一個範圍,也就是要判斷此IP的全部地。 例如:查詢IP是否存在的問題; ADSM,查詢IP是否在其餘分組中存在。寫json文件 sadd向名稱爲key的set中添加元素,返回影響元素的個數,0爲失敗,1爲成功 例如:有下面兩個範圍,10-20和30-40 ·         A_start 10, A_end 20 ·         B_start 30, B_end 40 咱們將這兩個範圍的起始位置存在Redis的Sorted Sets數據結構中,基本範圍起始值做爲score,範圍名加start和end爲其value值:  redis 127.0.0.1:6379> zadd ranges 10 A_start (integer) 1 redis 127.0.0.1:6379> zadd ranges 20 A_end (integer) 1 redis 127.0.0.1:6379> zadd ranges 30 B_start (integer) 1 redis 127.0.0.1:6379> zadd ranges 40 B_end (integer) 1     這樣數據在插入Sorted Sets後,至關因而將這些起始位置按順序排列好了。 如今我須要查找15這個值在哪個範圍中,只須要進行以下的zrangbyscore查找:  redis 127.0.0.1:6379> zrangebyscore ranges (15 +inf LIMIT 0 1 1) "A_end"     這個命令的意思是在Sorted Sets中查找大於15的第一個值。(+inf在Redis中表示正無窮大,15前面的括號表示>15而非>=15) 查找的結果是A_end,因爲全部值是按順序排列的,因此能夠斷定15是在A_start到A_end區間上,也就是說15是在A這個範圍裏。至此大功告成。 固然,若是你查找到的是一個start,好比我們用25,執行下面的命令  redis 127.0.0.1:6379> zrangebyscore ranges (25 +inf LIMIT 0 1 1) "B_start"     返回結果代表其下一個節點是一個start節點,也就是說25這個值不處在任何start和end之間,不屬於任何範圍。 11.存儲社交關係 Sina實例 l hash sets: 關注列表, 粉絲列表, 雙向關注列表(key-value(field), 排序) l string(counter): 微博數, 粉絲數, ...(避免了select count(*) from ...) l sort sets(自動排序): TopN, 熱門微博等, 自動排序 l lists(queue): push/sub新提醒,...  12.交集,並集,差集:(Set) //book表存儲book名稱 set book:1:name    」The Ruby Programming Language」 set book:2:name     」Ruby on rail」 set book:3:name     」Programming Erlang」 //tag表使用集合來存儲數據,由於集合擅長求交集、並集 sadd tag:ruby 1 sadd tag:ruby 2 sadd tag:web 2 sadd tag:erlang 3 //即屬於ruby又屬於web的書?  inter_list = redis.sinter("tag.web", "tag:ruby") //即屬於ruby,但不屬於web的書?  inter_list = redis.sdiff("tag.ruby", "tag:web") //屬於ruby和屬於web的書的合集?  inter_list = redis.sunion("tag.ruby", "tag:web") 5.   Redis Tools 1.8. 實用命令 l Keys * : 返回全部的key,* 可以使用正則表達式查詢 l Type key :返回key的類型(string ,zset ,list) l Select 1 : 選擇第一個數據庫;默認0-15個數據庫;默認是第0個數據庫庫中 l Dbsize : 當前數據庫中的key的個數 l Monitor : 監控收到的請求 1.9. phpRedisAdmin 相似phpmyadmin是一個PHP的MySQL WEB管理工具,是一個PHP的Redis WEB管理工具。 圖例:   1.10.   RedBridge: 爲Redis提供HTTP API及鏈接池功能 RedBridge 是一款基於Redis的 HTTP API。使用LUA直接跟Redis交互,對Redis的鏈接實現鏈接池。(相似數據庫的存儲過程) 高效的實現複雜的業務邏輯。 特性介紹 RedBridge 具備如下特徵: 1. 使用C+epoll 編寫的Web Server,支持HTTP GET操做 2. 鏈接池,鏈接句柄複用,提升跟Redis鏈接效率 3. 部分類庫使用Redis的代碼,更加的穩定 4. 使用LUA直接調用Redis命令,實現一次性數據交互實現 複雜的業務邏輯。不須要屢次數據交互 5. 服務模型採用單進程,雙線程模式 6. 配置文件採用Lua 語法,容易讀取和書寫 7. RedBridge發佈前,尚未相似的開源項目    轉自 heoo 的 Redis特性和應用場景
計算機類博客

這裏就要拋出一個問題來:機器學習:你到底須要多少訓練數據,尤爲是SVM?json

我這裏訓練集加起來才889篇,能夠明確的是這些訓練集是確定不夠的,理論上來講訓練集應該越多越好,可是其分類想過應該是一個愈來愈平緩的曲線,這個貌似應該研究起來也是一個很多篇幅的內容。api

三,開始特徵提取吧!

接下來就開始機器學習第一步也是最重要的一步,也是最麻煩的一步吧,事實上本身要作的工做就是這一步。畢竟後面的訓練只要用前輩們已經不斷完善的分類算法和工具了,我選擇的是SVM算法和libsvm工具包。

再聲明一下,我是利用卡方檢驗對須要進行二分類的文本進行特徵選擇,已達到降維的目的,最終要獲得的是可以表明每一個類別的特徵集合,和一個總的特徵詞典。固然在這個工程中,咱們也會看到每一個詞對於一個文本重要性的規律。

1.分詞工具 

第一步:選擇分詞工具對訓練集進行分詞

我選擇的分詞工具是JIEba分詞,而我使用的語言是C# ,關於.net core版本的JIEba分詞能夠在這篇博文裏面找到:

http://www.cnblogs.com/dacc123/p/8431369.html

利用JIEba分詞工具,咱們才能進行後面的計算詞頻,詞的文檔頻率,詞的四表格值,詞的卡方值χ2   。這裏仍是把本身的代碼貼出來吧,若是有須要的話我會整理在GitHub上。

2.計算詞頻 

第二步:計算詞頻

相信你們都會寫,我把本身代碼貼出來以供參考,代碼中多用了Dictionary 數據結構,對了分詞以前,我們應該有一份比較全的停用詞表。插一句:對於文本分類來講停用詞越多越好,對於搜索引擎來講就不是這樣了。

1800多個停用詞

!
"
#
$
%
&
'
(
)
*
+
,
-
--
.
..
...
......
...................
./
.一
.數
.日
/
//
0
1
2
3
4
5
6
7
8
9
:
://
::
;
<
=
>
>>
?
@
A
Lex
[
\
]
^
_
`
exp
sub
sup
|
}
~
~~~~
·
×
×××
Δ
Ψ
γ
μ
φ
φ.
В
—
——
———
‘
’
’‘
「
」
」,
…
……
…………………………………………………③
′∈
′|
℃
Ⅲ
↑
→
∈[
∪φ∈
≈
①
②
②c
③
③]
④
⑤
⑥
⑦
⑧
⑨
⑩
──
■
▲
 
、
。
〈
〉
《
》
》),
」
『
』
【
】
〔
〕
〕〔
㈧
一
一.
一一
一下
一個
一些
一何
一切
一則
一則經過
一天
必定
一方面
一旦
一時
一來
同樣
一次
一片
一番
一直
一致
通常
一塊兒
一轉眼
一邊
一面
七
萬一
三
三天兩頭
三番兩次
三番五次
上
上下
上升
上去
上來
上述
上面
下
下列
下去
下來
下面
不
不一
不下
不久
不了
不亦樂乎
不只
不只...並且
不只僅
不只僅是
不會
不但
不但...並且
不光
難免
再也不
不力
不單
不變
不僅
不可
不可開交
不可抗拒
不一樣
不外
不外乎
不夠
不大
不如
不妨
不定
不對
很多
不盡
不盡然
不巧
不已
不常
不得
不得不
不得了
不得已
沒必要
不怎麼
不怕
不唯
不成
不拘
不擇手段
不敢
不料
不斷
不日
不時
不是
未曾
不止
不止一次
不比
不消
不滿
否則
否則的話
不特
不獨
不禁得
不知不覺
無論
無論怎樣
不經意
不勝
不能
不能不
不至於
不若
不要
不論
不起
不足
不過
不迭
不問
不限
與
與其
與其說
與否
與此同時
專門
且
且不說
且說
二者
嚴格
嚴重
個
我的
個別
中小
中間
豐富
串行
臨
臨到
爲
爲主
爲了
爲何
爲什麼
爲什麼
爲止
爲此
爲着
主張
主要
舉凡
舉行
乃
乃至
乃至於
麼
之
之一
以前
以後
之後
之因此
之類
烏乎
乎
乒
乘
乘勢
伺機
乘勝
乘虛
乘隙
九
也
也好
也就是說
也是
也罷
了
瞭解
爭取
二
二來
二話不說
二話沒說
於
因而
因而乎
云云
云爾
互
互相
五
些
交口
亦
產生
親口
親手
親眼
親自
親身
人
人人
人們
人家
人民
什麼
什麼樣
什麼
僅
僅僅
今
從此
今天
今年
今後
介於
仍
仍舊
仍然
從
從不
從嚴
從中
從事
從今之後
從優
古往今來
從古至今
從頭
從寬
從小
重新
從無到有
從早到晚
從未
歷來
今後
今後之後
從而
從輕
從速
從重
他
他人
他們
他是
他的
代替
以
以上
如下
覺得
以便
以避免
之前
以及
之後
之外
以後
以故
以期
以來
以致
以致於
以至
們
任
任何
任憑
任務
企圖
夥同
會
偉大
傳
傳說
傳聞
彷佛
似的
但
但凡
希望
可是
何
何樂而不爲
何以
況且
何處
何妨
未嘗
何須
什麼時候
何止
何苦
何必
餘外
做爲
你
大家
你是
你的
使
使得
使用
例如
依
依據
依照
依靠
便
便於
促進
保持
保管
保險
俺
俺們
倍加
倍感
倒不如
倒不如說
卻是
倘
倘使
倘或
倘然
假若
借
藉以
藉此
假使
假如
倘若
恰恰
作到
偶爾
偶而
儻然
像
兒
容許
元/噸
充其極
充其量
充分
先不先
前後
先後
先生
光
光是
全體
全力
整年
全然
全身心
所有
全都
全面
八
八成
公然
六
兮
共
共同
共總
關於
其
其一
其中
其二
其餘
其他
其後
其它
其實
其次
具體
具體地說
具體來講
具體說來
具備
兼之
內
再
再其次
再則
再有
再次
再者
再者說
再說
冒
衝
決不
決定
決非
何況
準備
湊巧
凝神
幾
幾乎
幾度
幾時
幾番
幾經
凡
凡是
憑
憑藉
出
出於
出去
出來
出現
分別
分頭
分期
分期分批
切
切不可
切切
切勿
切莫
則
則甚
剛
恰好
剛巧
剛纔
初
別
別人
別處
別是
別的
別管
別說
到
到了兒
處處
到頭
到頭來
到底
到目前爲止
先後
前此
前者
前進
前面
加上
加之
加以
加入
增強
動不動
動輒
勃然
匆匆
十分
千
千萬
千萬千萬
半
單
單單
單純
即
即令
即便
即使
即刻
即如
即將
即或
便是說
即若
卻
卻不
歷
原來
去
又
又及
及
及其
及時
及至
雙方
反之
反之亦然
反之則
反倒
反卻是
反應
反手
反映
反而
反過來
反過來講
取得
取道
受到
變成
古來
另
另外一個
另外一方面
另外
另悉
另方面
另行
只
只當
只怕
只是
只有
只消
只要
只限
叫
叫作
召開
叮咚
叮噹
可
能夠
可好
但是
可能
可見
各
各個
各人
各位
各地
各式
各類
各級
各自
合理
同
同一
同時
一樣
後
後來
後者
後面
向
向使
向着
嚇
嗎
不然
吧
吧噠
吱
呀
呃
呆呆地
吶
嘔
唄
嗚
嗚呼
呢
周圍
呵
呵呵
呸
呼哧
呼啦
咋
和
咚
咦
咧
咱
我們
咳
哇
哈
哈哈
哉
哎
哎呀
哎喲
譁
嘩啦
喲
哦
哩
哪
哪一個
哪些
哪兒
哪天
哪年
哪怕
哪樣
哪邊
哪裏
哼
哼唷
唉
惟有
啊
啊呀
啊哈
啊喲
啐
啥
啦
啪達
啷噹
喀
喂
喏
喔唷
嘍
嗡
嗡嗡
嗬
嗯
噯
嘎
嘎嘎
嘎登
噓
嘛
嘻
嘿
嘿嘿
四
因
由於
因了
所以
因着
於是
固
當然
在
在下
在於
地
均
堅定
堅持
基於
基本
基本上
處在
到處
處理
複雜
多
多麼
多虧
多多
多多少少
多多益善
多少
多年前
多年來
多數
屢次
夠瞧的
大
大不了
大舉
大事
大致
大致上
大凡
大力
大多
大多數
大大
你們
大張旗鼓
大批
大抵
大概
大略
大約
大體
大都
大量
大面兒上
失去
奇
奈
奮勇
她
她們
她是
她的
好
好在
好的
好象
如
如上
如上所述
以下
現在
如何
如其
如前所述
如同
如常
如是
如期
若是
如次
如此
如此等等
如若
始而
姑且
存在
存心
孰料
孰知
寧
寧肯
寧願
寧可
它
它們
它們的
它是
它的
安全
徹底
完成
定
實現
實際
宣佈
容易
密切
對
對於
對應
對待
對方
對比
將
將才
將要
將近
小
少數
爾
爾後
爾爾
爾等
尚且
尤爲
就
就地
就是
就是了
就是說
就此
就算
就要
盡
儘量
盡如人意
全力以赴
盡心竭力
儘快
儘早
盡然
儘管
儘管如此
儘可能
局外
竟然
屆時
屬於
屢
屢屢
多次
多次三番
豈
豈但
豈止
豈非
川流不息
左右
巨大
鞏固
差一點
差很少
己
已
已矣
已經
巴
巴巴
帶
幫助
常
經常
常言說
常言說得好
常言道
平素
年復一年
並
並不
並非
而且
並排
並沒有
並沒
並無
並肩
並不是
廣大
普遍
應當
應用
應該
庶乎
庶幾
開外
開始
開展
引發
弗
彈指之間
強烈
強調
歸
歸根到底
歸根結底
歸齊
當
當下
當中
當兒
當前
立即
當口兒
當地
當場
當頭
當庭
當時
固然
當真
當着
造成
徹夜
完全
彼
彼時
彼此
往
每每
待
待到
很
不少
不多
後來
後面
得
得了
得出
獲得
得天獨厚
得起
內心
必
一定
必將
必然
必要
必須
快
快要
忽地
突然
怎
怎麼
怎麼辦
怎麼樣
怎奈
怎樣
怎麼
怕
急匆匆
怪
怪不得
總之
老是
總的來看
總的來講
總的說來
總結
總而言之
恍然
恐怕
恰似
剛好
恰如
恰巧
偏偏
偏偏相反
恰逢
您
您們
您是
唯其
慣常
意思
憤然
願意
慢說
成爲
成年
成年累月
成心
我
咱們
我是
個人
或
或則
或多或少
或是
或曰
或者
或許
戰鬥
截然
截至
所
因此
所在
所幸
全部
所謂
才
才能
撲通
打
打從
打開天窗說亮話
擴大
把
抑或
抽冷子
攔腰
拿
按
按時
定期
按照
按理
按說
挨個
挨家挨戶
挨次
挨着
挨門挨戶
挨門逐戶
換句話說
換言之
據
據實
據悉
據我所知
據此
據稱
聽說
掌握
接下來
接着
接著
接連不斷
放量
故
故意
故此
故而
敞開兒
敢
勇於
敢情
數/
整個
斷然
方
方便
方纔
方能
方面
旁人
無
無寧
沒法
不管
既
既...又
既往
既是
既然
日復一日
日漸
日益
日臻
日見
時候
昂然
明顯
明確
是
是否是
是以
是否
是的
顯然
顯著
普通
廣泛
暗中
暗地裏
暗自
更
更爲
更加
更進一步
曾
曾經
替
替代
最
最後
最大
最好
最後
最近
最高
有
有些
有關
有利
有力
有及
有所
有效
有時
有點
有的
有的是
有着
有著
望
朝
朝着
末##末
本
本人
本地
本着
自己
權時
來
來不及
來得及
來看
來着
來自
來說
來講
極
極爲
極了
極其
極力
極大
極度
極端
構成
果真
果然
某
某個
某些
某某
根據
根本
格外
梆
概
次第
歡迎
歟
正值
正在
正如
正巧
正常
正是
此
此中
此後
此地
此處
此外
此時
這次
此間
殆
毋寧
每
每一個
天天
每一年
每當
每時每刻
往往
每逢
比
比及
好比
好比說
比方
比照
比起
比較
畢竟
絕不
毫無
毫無例外
毫無保留地
汝
沙沙
沒
沒奈何
沒有
沿
沿着
注意
活
深刻
清楚
滿
知足
漫說
焉
然
然則
而後
然後
然而
照
照着
緊緊
特別是
特殊
特色
猶且
猶自
獨
獨自
猛然
猛然間
率爾
率然
現代
如今
理應
理當
理該
瑟瑟
甚且
甚麼
甚或
甚而
甚至
甚至於
用
用來
甫
甭
由
因爲
由是
由此
因而可知
略
略爲
略加
略微
白
白白
的
的確
的話
皆可
目前
直到
直接
類似
相信
相反
相同
相對
相對而言
相應
至關
相等
免得
看
看上去
看出
看到
看來
看樣子
看看
看見
看起來
真是
真正
眨眼
着
着呢
矣
矣乎
矣哉
知道
砰
肯定
碰巧
社會主義
離
種
積極
移動
究竟
窮年累月
突出
忽然
竊
立
馬上
當即
立地
立時
立馬
竟
居然
竟而
第
第二
等
等到
等等
策略地
簡直
簡而言之
簡言之
管
類如
粗
精光
緊接着
累年
累次
純
純粹
縱
縱令
縱使
縱然
練習
組成
經
常常
通過
結合
結果
給
絕
毫不
絕對
絕非
絕頂
繼之
繼後
繼續
繼而
維持
綜上所述
縷縷
罷了
老
老大
總是
老老實實
考慮
者
而
並且
而況
而又
然後
而外
而已
而是
而言
而論
聯繫
聯袂
背地裏
背靠背
能
可否
可以
騰
自
自個兒
自從
自各兒
自後
自家
本身
自打
自身
臭
至
至於
至今
至若
致
般的
良好
若
若夫
如果
若果
若非
範圍
莫
莫不
莫否則
莫如
莫若
莫非
得到
藉以
雖
雖則
雖然
雖然說
蠻
行爲
行動
代表
表示
被
要
要不
要不是
要否則
要麼
要是
要求
見
規定
以爲
譬喻
譬如
認爲
認真
認識
讓
許多
論
論說
設使
設或
設若
誠如
誠然
話說
該
該當
說明
說來
說說
請勿
諸
諸位
諸如
誰
誰人
誰料
誰知
謹
豁然
賊死
賴以
趕
趕快
趕早不趕晚
起
起先
起初
起頭
起來
起見
起首
趁
趁便
趁勢
趁早
趁機
趁熱
趁着
越是
距
跟
路經
轉動
轉變
轉貼
轟然
較
較爲
較之
較比
邊
達到
達旦
迄
迅速
過
過於
過去
過來
運用
近
近幾年來
近年來
近來
還
仍是
還有
還要
這
這一來
這個
這麼
這麼些
這麼樣
這麼點兒
這些
這會兒
這兒
這就是說
這時
這樣
此次
這點
這種
這般
這邊
這裏
這麼
進入
進去
進來
進步
進而
進行
連
連同
連聲
連日
連日來
連袂
連連
早晚
迫於
適應
適當
適用
逐步
逐漸
一般
經過
形成
逢
遇到
遭到
遵循
遵守
避免
那
那個
那麼
那麼些
那麼樣
那些
那會兒
那兒
那時
那末
那樣
那般
那邊
那裏
那麼
部分
都
鄙人
採起
裏面
重大
從新
重要
鑑於
針對
長期以來
長此下去
長線
長話短說
問題
間或
防止
阿
附近
陳年
限制
陡然
除
除了
除卻
除去
除外
除開
除此
除此以外
除此之外
除此而外
除非
隨
隨後
隨時
隨着
隨著
隔夜
隔日
可貴
難怪
難說
難道
難道說
集中
零
須要
非但
很是
非徒
非得
非特
非獨
靠
頂多
頃
頃刻
頃刻之間
頃刻間
順
順着
頓時
頗
風雨無阻
飽
首先
立刻
高低
高興
默然
默默地
齊
︿
!
#
$
%
&
'
(
)
)÷(-
)、
*
+
+ξ
++
,
,也
-
-β
--
-[*]-
.
/



12








:
;
<
<±
<Δ
<λ
<φ
<<
=
=″
=☆
=(
=-
=[
={
>
>λ
?
@
A
LI
R.L.
ZXFITL
[
[①①]
[①②]
[①③]
[①④]
[①⑤]
[①⑥]
[①⑦]
[①⑧]
[①⑨]
[①A]
[①B]
[①C]
[①D]
[①E]
[①]
[①a]
[①c]
[①d]
[①e]
[①f]
[①g]
[①h]
[①i]
[①o]
[②
[②①]
[②②]
[②③]
[②④
[②⑤]
[②⑥]
[②⑦]
[②⑧]
[②⑩]
[②B]
[②G]
[②]
[②a]
[②b]
[②c]
[②d]
[②e]
[②f]
[②g]
[②h]
[②i]
[②j]
[③①]
[③⑩]
[③F]
[③]
[③a]
[③b]
[③c]
[③d]
[③e]
[③g]
[③h]
[④]
[④a]
[④b]
[④c]
[④d]
[④e]
[⑤]
[⑤]]
[⑤a]
[⑤b]
[⑤d]
[⑤e]
[⑤f]
[⑥]
[⑦]
[⑧]
[⑨]
[⑩]
[*]
[-
[]
]
]∧′=[
][
_
a]
b]
c]
e]
f]
ng昉
{
{-
|
}
}>
~
~±
~+
¥
 
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
停用詞表

計算詞頻代碼:

       public void ReadText()
        {
            rd = File.OpenText("./stopwords.txt");
            string s = "";
            while ((s = rd.ReadLine()) != null)
            {
                if (s == null) continue;
                if (!stopwords.ContainsKey(s))
                    stopwords.Add(s, 1);
            }
            Console.WriteLine("*******讀取停用詞完畢");
            rd.Close();

        }

        //計算詞頻,url1地址是放入訓練集的文件夾,url2地址是存放計算詞頻結果的文件
        public void WriteText(string url1, string url2)
        {

            DirectoryInfo folder = new DirectoryInfo(url1);
            foreach (FileInfo file in folder.GetFiles("*.txt"))
            {

                rd = File.OpenText(file.FullName);
                string s = "";
                System.Console.WriteLine("**************開始讀取數據...");
                while ((s = rd.ReadLine()) != null)
                {
                    var segment = segmenter.Cut(s, false, false);

                    foreach (var x in segment)
                    {
                        if (stopwords.ContainsKey(x)) continue;
                        if (!keys.ContainsKey(x))
                            keys.Add(x, 1);
                        else
                            keys[x]++;
                    }

                }
            }
            System.Console.WriteLine("**************讀取完畢,計算詞頻並插入...");
            wt = new StreamWriter(url2, true);
            //wt = File.AppendText(url2);
            var dicSort = from objDic in keys orderby objDic.Value descending select objDic;
            foreach (KeyValuePair<string, int> kvp in dicSort)
            {
                wt.WriteLine(kvp.Key + " " + kvp.Value.ToString());

            }
            System.Console.WriteLine("**************插入完畢...");
            wt.Flush();
            rd.Close();
            wt.Close();

        }

通過一頓操做:

 歷史類:                                     計算機博客類:

選擇詞頻排名前30的詞,來看看,排名靠前的詞乍一看好像貌似是那麼回事,這也是有時候你只用詞頻這一個屬性來分類文本,發現效果也不是那麼差。仔細看一下:

歷史類:「標」,「題」,「年」....等等,計算機博客類:「中」,「時」,等等這些詞老是那麼的刺眼,咱們須要把這些冒充上來的詞給去掉。

忘了說下,計算機博客類的詞的個數是:21503個;歷史類的詞的個數是:68912個,因爲本身找的訓練集不是那麼好因此兩種類的詞差異有點大。。

詞的個數這麼多,若是用詞頻排序的詞表來當作特徵集,是否是效果不能到達最好,並且維度太大了。

 3.文檔頻率DF

前面提到過一個名詞:文檔頻率DF ,也就是一個詞在多少個文檔中出現過,對於那些文檔頻率十分低的詞,咱們叫作生僻詞,這些詞有可能詞頻很高,好比一我的寫博客:「我是大牛,我是大牛,我是大牛.....」循環了幾千次,那麼「大牛」這個詞就很靠前了,然而他只出現過在一篇博客裏,因此咱們能夠把這些生僻詞去掉。我也統計了兩個類別中的生僻詞,發現一大半都是DF爲1,2的詞。這裏也就不貼代碼和統計結果了,由於咱們不須要取出文檔頻率低的詞,爲何呢?由於有卡方檢驗啊,這個十分強大的機器,是確定會幫咱們過濾掉DF極低的詞,因此我們直奔卡方檢驗,看看是否是能夠驗證本身的猜測。(而統計DF的值偏偏幫助了咱們計算卡方檢驗)

 4.卡方檢驗 一

根據上一篇博客中的公式,對於每一個詞,咱們須要計算四個值,A,B,C,D。

再解釋一下,以「大牛」和計算機博客類爲例子:A 包含「大牛」屬於計算機博客的文檔個數,B 包含「大牛」不屬於計算機博客的文檔個數,C 不包含「大牛」屬於計算機博客類的文檔個數,D 不包含「大牛」不屬於計算機的文檔個數。

看起來很繁瑣,其實只要有了上一步統計的DF表,那就很容易了。以計算機博客類爲例子:

BlogDF 表示計算機博客類的詞的文檔頻率表,HistoryDF表示歷史類的詞的文檔頻率表

那麼A的值天然就是BlogDF的值

B的值:

forearch BlogDF

      if(HistoryDF[x]!=0)

      B[x] =  HistoryDF[x];

     else

          B[x] = 0;

C 和D 的值天然就是:

foreach C,D

       C[x] = 計算機總文檔數-A[x]

       D[x] = 計算機總文檔數-B[x]

 

代碼以下:比較簡陋沒有收拾

 public static Dictionary<string, int> keysA = new Dictionary<string, int>();
        public static Dictionary<string, int> keysB = new Dictionary<string, int>();

        public static Dictionary<string, int> keys2 = new Dictionary<string, int>();
        public static Dictionary<string, int> keysC = new Dictionary<string, int>();
        public static Dictionary<string, int> keysD = new Dictionary<string, int>();
        public static Dictionary<string, double> result = new Dictionary<string, double>();
        public static Dictionary<string, int> stopwords = new Dictionary<string, int>();
        public static System.IO.StreamReader rd;
        public static System.IO.StreamWriter wt;
        public JiebaSegmenter segmenter = new JiebaSegmenter();

        //屬於類別一訓練集的個數
        public static int category1=0;
        //屬於類別而訓練集的個數
        public static int category2=0;
        //先讀取記錄
        public void ReadText(string url,string url2)
        {
            rd = File.OpenText("./stopwords.txt");
            string s = "";
            while ((s = rd.ReadLine()) != null)
            {
                if (s == null) continue;
                if (!stopwords.ContainsKey(s))
                    stopwords.Add(s, 1);
            }
            Console.WriteLine("*******讀取停用詞完畢");
            rd.Close();

            rd = File.OpenText(url);
            s = "";
            while ((s = rd.ReadLine()) != null)
            {
                string s1 = ""; string s2 = "";
                int tag = 0;
                int l = s.Length;
                for (int i = 0; i < l; i++)
                {
                    if (s[i] == ' ')
                    {
                        tag = 1;
                        continue;
                    }
                    if (tag == 0)
                    {
                        s1 += s[i];
                    }
                    else
                        s2 += s[i];

                }

                keysA.Add(s1, Int32.Parse(s2));
            }
            rd.Close();

            rd = File.OpenText(url2);
            s = "";
            while ((s = rd.ReadLine()) != null)
            {
                string s1 = ""; string s2 = "";
                int tag = 0;
                int l = s.Length;
                for (int i = 0; i < l; i++)
                {
                    if (s[i] == ' ')
                    {
                        tag = 1;
                        continue;
                    }
                    if (tag == 0)
                    {
                        s1 += s[i];
                    }
                    else
                        s2 += s[i];

                }

                keys2.Add(s1, Int32.Parse(s2));
            }
            rd.Close();
            
            Console.WriteLine("*******加載舊記錄完畢");

            foreach(var x in keysA)
            {
                if(keys2.ContainsKey(x.Key))
                    keysB.Add(x.Key,keys2[x.Key]);
                else
                    keysB.Add(x.Key,0);
            }
        }

        //寫入特徵
        public void WriteText(string url1, string url2,string url3,string url4)
        {

            DirectoryInfo folder = new DirectoryInfo(url1);
            foreach (FileInfo file in folder.GetFiles("*.txt"))
            {
                category1++;
            }
             DirectoryInfo folder2 = new DirectoryInfo(url2);
            foreach (FileInfo file in folder2.GetFiles("*.txt"))
            {
                category2++;
            }

            foreach(var x in keysA)
            {
                keysC.Add(x.Key,category1-keysA[x.Key]);
                keysD.Add(x.Key,category2-keysB[x.Key]);
            }
           

            ComputeChi();
            if(!File.Exists(url3))
            {
                FileStream fs = File.Create(url3);
                fs.Close();
            }
            if(!File.Exists(url4))
            {
                FileStream fs = File.Create(url4);
                fs.Close();
            }
            System.Console.WriteLine("**************讀取完畢,計算A,B,C,D並插入...");
            wt = new StreamWriter(url3, false);
            //wt = File.AppendText(url2);
            var dicSort = from objDic in keysA orderby objDic.Value descending select objDic;
            foreach (KeyValuePair<string, int> kvp in dicSort)
            {
                wt.WriteLine(kvp.Key + " " + kvp.Value.ToString()+" "+keysB[kvp.Key]+" "+keysC[kvp.Key]+" "+keysD[kvp.Key]);
            }

            System.Console.WriteLine("**************插入完畢...");
            wt.Flush();

            System.Console.WriteLine("**************讀取完畢,計算卡方檢驗並插入...");
            wt = new StreamWriter(url4, false);
            //wt = File.AppendText(url2);
            var dicSort2 = from objDic in result orderby objDic.Value descending select objDic;
            foreach (KeyValuePair<string, double> kvp in dicSort2)
            {
                wt.WriteLine(kvp.Key + " " + kvp.Value.ToString());
            }

            System.Console.WriteLine("**************插入完畢...");
            wt.Flush();


            rd.Close();
            wt.Close();

        }

        public static void ComputeChi()
        {
            foreach(var x in keysA)
            {
result.Add(x.Key,(double)((double)(category1+category2)*((double)keysA[x.Key]*keysD[x.Key]-(double)keysB[x.Key]*keysC[x.Key])*((double)keysA[x.Key]*keysD[x.Key]-(double)keysB[x.Key]*keysC[x.Key]))/
((double)(keysA[x.Key]+keysB[x.Key])*(double)(keysC[x.Key]+keysD[x.Key])*(double)(keysA[x.Key]+keysC[x.Key])*(double)(keysB[x.Key]+keysD[x.Key])));
            }

        }
計算卡方檢驗

因而興高采烈的看看咱們的強大的卡方檢驗獲得的值,以計算機類:爲了作對比,左邊是詞頻排名,右邊的是卡方檢驗排名

 

 

頓時傻眼了,爲何卡方檢驗 以後,詞的排名變成這樣了?「歷史」,「中國」,「發展」,貌似是表明的歷史了,難道本身代碼寫錯了?仔細排查發現代碼並無寫錯,這些詞也確實在計算機博客類別的文檔裏出現過。但是爲何這些詞的排名如此之高?

查找這些的A,B,C,D值,以「標」爲例

  屬於計算機類博客 不屬於計算機類博客(屬於歷史類)
包含「標」 A:3 B:443
不包含「標」 C:417 D:26

 

根據公式,計算出來的值確實是780多,而標的詞頻只有:3!!。翻看歷史類別的卡方值也是780多,這個「標」這麼全能嗎?(實際上兩個類別的公共詞的卡方值都是同樣的,觀察公式和ABCD的值就能夠發現了)

咱們再回顧一開始的卡方檢驗:咱們假設某個詞對於文檔是否是某個類別是沒有影響的,而不是某個詞是否是能表明某個類別,那麼「標」這個詞雖然對計算機博客類幾乎沒有一點表明性,可是你看看以前的詞頻表,「標」在歷史類中的詞頻排名很是靠前。到這裏就應該清楚了「標」這個詞,卡方檢驗認爲「標」這個詞對歷史類別的影響很大,當一個文檔出現「標」那麼能夠很大一部分肯定他是歷史類別,不是計算機博客類別,因此「標」對於文檔不是計算機類別仍是有很大影響力的,天然排名靠前。這裏就有一個疑問了,爲何「標」這種詞能夠很好的表明歷史?這個後面再提,這也是前面說過的卡方檢驗的低詞頻性缺陷

5.卡方檢驗二

因此眼前這個酷似歷史的卡方檢驗排名表,是否能夠做爲計算機博客類的特徵集合呢?答案是確定的,這些排名靠前的詞對於判斷一個文檔是否屬於計算機博客類別至關有說服力。 可是這樣的排名表,我看着真的不是很喜歡。

因而我就作了點小動做。咱們回顧一下卡方檢驗公式推導過程,

 

爲了防止正負相互抵消,因此咱們採用了平方和。而後在二分類問題中,這個正負實際上是頗有意義的,不該該就這麼被和諧掉。咱們看看「標」的四格表

  屬於計算機類博客 不屬於計算機類博客(屬於歷史類)
包含「標」 A:3 B:443
不包含「標」 C:417 D:26

A和D的值很小,B和C的值很大,這就告訴了咱們一個信息含有「標」很大多是歷史類,很小多是計算機類,在計算過程當中:

以計算A的觀察值和理論值的誤差爲例(約等於):

 

實際上這個誤差應該是負的,3-210應該是負數,咱們使用平方和才變成爲正的,因此咱們不使用平方和而是使用(E-A)*|(E-A)| 

誤差爲負表示啥呢,表示這個詞可以否認文本屬於該類文檔(語氣重了一點),爲正表示這個詞可以確定文本屬於該類文檔。

 

  屬於計算機類博客 不屬於計算機類博客(屬於歷史類)
包含「標」 A:3  EA:210 B:443 EB:235
不包含「標」 C:417 EC : 209 D:26  ED:233

推廣到四個值,發現實際上B的誤差值是正的 443-235是正數嘛,實際上對於B咱們應該取負數,同理C應該去負數。對於B,C在計算結果以後加上一個負數

這樣算出來的標就是-780多。爲何呢?由於B是包含「標」屬於歷史類,對於計算機類說是反例,同理C也是,因此要取反,正變負,負變正。

這樣咱們能夠想象,若是用符號表示卡方值的大小,那麼卡方檢驗獲得的值應該是相似於正態分佈:

 

 

靠近0的詞越沒有用,離0越遠的詞咱們就越關注。那麼這個具體的閥值是什麼?還記得在卡方分佈中說過的那個拒絕域嗎?

 

3.84,對就是他了。你別看上面的圖+3.84 和-3.84之間距離很短,可是這麼短的距離中包含的詞可多着呢,個人數據集中,大概三分之二的詞都集中在-3.84到+3.84之間

因而在這個有符號的卡方檢驗指導下,咱們變動公式!(對於四格表而言哦,也就是對於二分類而言哦)

根據此公式,咱們修改代碼

   //計算觀察值A的誤差 符號爲+
                double EA = (double)(keysA[x.Key]+keysB[x.Key])*(double)(keysA[x.Key]+keysC[x.Key])/(double)(category1+category2);
                double a = (double)(keysA[x.Key]-EA)*System.Math.Abs((double)(keysA[x.Key]-EA))/EA;
               
                //計算觀察值B的誤差 符號爲-
                double EB = (double)(keysA[x.Key]+keysB[x.Key])*(double)(keysB[x.Key]+keysD[x.Key])/(double)(category1+category2);
                double b = -1*(double)(keysB[x.Key]-EB)*System.Math.Abs((double)(keysB[x.Key]-EB))/EB;
               

                //計算觀察值C的誤差 符號爲-
                double EC = (double)(keysC[x.Key]+keysD[x.Key])*(double)(keysA[x.Key]+keysC[x.Key])/(double)(category1+category2);
                double c = -1*(double)(keysC[x.Key]-EC)*System.Math.Abs((double)(keysC[x.Key]-EC))/EC;
                

                //計算觀察值D的誤差 符號爲+
                double ED = (double)(keysC[x.Key]+keysD[x.Key])*(double)(keysB[x.Key]+keysD[x.Key])/(double)(category1+category2);
                double d = (double)(keysD[x.Key]-ED)*System.Math.Abs((double)(keysD[x.Key]-ED))/ED;
               

                result.Add(x.Key,a+b+c+d);

獲得一個新的卡方檢驗表,以計算機類別,一樣和詞頻做對比

 

乍一看,卡方檢驗的效果確實不錯,仔細一看,嗯仍是效果很好。哈哈哈。「中」這個詞終於消失了。果真名不虛傳 ,卡方檢驗確實是一個好東西

6.卡方檢驗的低詞頻性

再看看歷史類的:

 

哎呀,這個「標」,「期」 ....等等,真是差強人意。看看以前的文本範例,咱們就明白了

【 文獻號 】1-1
【原文出處】歷史研究
【原刊地名】京
【原刊期號】199602
【原刊頁號】5-25
【分 類 號】K1
【分 類 名】歷史學
【 做  者 】林甘泉
【複印期號】199607
【 標  題 】二十世紀中國歷史學回顧  二十世紀的中國歷史學
【 正  文 】

每一篇都有一個「標題」,「文獻號」等等,由於卡方檢驗原本就是忽視了詞頻的,此次個每篇文章只出現一次的詞,反而重要性排第一去了。因此咱們就須要結合詞頻信息,對卡方檢驗再次來改造。具體應該怎麼權衡卡方檢驗和詞頻的值呢?一時間我也沒有想到好的方法。能夠將卡方檢驗排名靠前的詞,詞頻小於等於文檔數,或者小於等於文檔數2倍的詞都去掉。

 7.卡方檢驗的神奇

再來看看卡方檢驗排名表的後半部分,左邊計算機博客類,右邊歷史類!

 

能夠看到,這些歷史類排名最後的是否是很像是計算機博客類的詞語?這些距離0很遠的詞,是論證文章不屬於歷史類的詞語,也驗證了上面的正態分佈的猜測。兩個類別正好倒過來了,十分對稱,十分完美。絕知此事要躬行,躬行以後的感受果真不一樣呀。

其實具體實驗的時候才發現,詞彙這個組成文章的基本成分,在衆多文本之間有太多規律,太多巧妙的地方值得去挖掘了,這也是天然語言處理的魅力了吧。

再次回到以前的文檔頻率DF,咱們說文檔頻率DF低的不用處理,卡方檢驗會幫我處理,看看結果,這裏截兩張圖:

第一個參數是卡方檢驗的值,第二個值是文檔頻率DF

 

果真這些DF十分低的詞都被分配到了0周圍,堅定的和0站在一塊兒,堅定的要被淘汰掉。

 

四,結語

那麼通過前面的步驟,的確獲得了能夠表明兩個類的特徵集合,將兩個特徵集合距離0的距離大於3.84的特徵(就是詞啦)取一個並集,那麼就是一個特徵詞典了。咱們能夠想象,歷史類和計算機博客類的文本向量若是映射在這個詞典上,他們分佈是不一樣的,而SVM正是解決中在高維空間(也就是向量維度很高),把兩類向量進行分類,若是線性不可分,SVM會使用核函數,映射到更高的維度使其變成線性可分。具體的原理這裏也不細究。可見在SVM以前,將文本變成向量的過程是一個很是重要的步驟。

相關文章
相關標籤/搜索