Decision Trees (6.4)
Entropy and Information Gain (6.4.1)
Try to execute entropy calculation sample.
>>> import nltk >>> from nltk_init import * >>> import math >>> def entoropy(labels): ... freqdist = nltk.FreqDist(labels) ... probs = [freqdist.freq(l) for l in nltk.FreqDist(labels)] ... return -sum([p * math.log(p,2) for p in probs]) ... >>> print entoropy(['male', 'male', 'male', 'male']) -0.0 >>> print entoropy(['male', 'female', 'male', 'female']) 1.0 >>> print entoropy(['female', 'female', 'male', 'female']) 0.811278124459 >>> print entoropy(['female', 'female', 'female', 'female']) -0.0 >>>
Let's do debugging for better understanding.
>>> import pdb >>> pdb.run("print entoropy(['male', 'male', 'male', 'male'])") > <string>(1)<module>()->None (Pdb) s --Call-- > <stdin>(1)entoropy() (Pdb) s > <stdin>(2)entoropy() (Pdb) s --Call-- > /Library/Python/2.7/site-packages/nltk/probability.py(85)__init__() -> def __init__(self, samples=None): (Pdb) r --Return-- > /Library/Python/2.7/site-packages/nltk/probability.py(105)__init__()->None -> self.update(samples) (Pdb) r > <stdin>(3)entoropy() (Pdb) p probs *** NameError: NameError("name 'probs' is not defined",) (Pdb) p [freqdist.freq(l) for l in nltk.FreqDist(labels)] [1.0]
This is frequency of 'male', therefore the value is 1.0.
(Pdb) s --Call-- > /Library/Python/2.7/site-packages/nltk/probability.py(85)__init__() -> def __init__(self, samples=None): (Pdb) r --Return-- > /Library/Python/2.7/site-packages/nltk/probability.py(105)__init__()->None -> self.update(samples) (Pdb) r > <stdin>(3)entoropy() (Pdb) p math.log(1.0,2) 0.0 (Pdb) q >>>
log 1 is always zero. Then the result was (-)0.0. Seems fine to understand. How about others? We can check to simulate the return from function entropy().
>>> 0.5 * math.log(0.5,2) -0.5 >>> 0.25 * math.log(0.25,2) -0.5 >>> 0.75 * math.log(0.75,2) -0.31127812445913283 ||< If the probability of 'male' and 'female' are 0.5 and 0.5, the return would be >|| -((-0.5)+(-0.5)) = 1.0
If 'male' vs 'female' are 0.75 and 0.25,
-((-0.5)+(-0.31127812445913283)) = 0.811278124459
Sounds reasonable.
あ、確率の話か (中国語の声調を推測してみる) その2
引っ張った昨日の話の続きです。
どんなデータを作ったのか。
チラ見せするとこんな感じ。
元となったデータは、ピンインを純粋な発音の部分(子音+母音)と4つある声調(あと軽声も)に分けてマトリックス状にしました。発音の種類は395種類あり、それぞれについて、第1声から第4声までの出現頻度を出してあります。と言っても、あまりサンプル数が少ないモノは参考にならないので、20回以上の頻度で使われたモノ(190/395種類)を参考データとして使うことにしました。
xin, cheng, gongは自信を持ってヤマを張ろう
一応前提の確認です。単純化して言うと、音は分かるけど声調が分からないときにヤマを張れるかというお話しです。結論から言うと、いくつかヤマを張っても大丈夫そうなものがあるようです。
例えば、xinという発音の漢字は、81.6%の確率で第1声となるようです。逆に言うと、とりあえず第1声で発音してしまえば、恥をかく確率は20%以下で済みそうです。
chengなんかはもっと顕著で、第2声の確率が90%を超えています。これならドヤ顔で第2声で発音しておけば、ほぼ大丈夫でしょう。
さらにこの中で言うと、gongも第1声となる字が80%を超えていますね。
有用かも知れないこの分析
データをざっと眺めた感じだと、第1声から第4声にまんべんなく散っている発音の方が少数派だと分かってきました。要は発音によって声調に偏りがあると。ちなみに全てをトータルすると、(日本人の苦手な)第3声は比率で言うとやや低め、代わりに第4声がやや多めみたいです。
実は、結構きちんと探求すれば結構な確率で正しい声調が推測できるようになるかも、、、なんて甘い考えを抱いてしまいました。
また、面白そうなネタがあったらご紹介したいと思います。
一応、HSK6級ホルダーとしてお勧めの参考書など。
- 作者: 株式会社スプリックス,国家漢弁/孔子学院総部
- 出版社/メーカー: スプリックス
- 発売日: 2012/02/11
- メディア: 単行本(ソフトカバー)
- 購入: 1人 クリック: 4回
- この商品を含むブログを見る
- 作者: 王素梅,新漢語水平考試の筆記模擬試験問題10セット収録。6級は語彙量5000語以上の常用詞語を把握し、中国語の情報をスムーズに読んだり聞いたりすることができ、会話や文章により、自分の見解を流暢に表現することができるレベル。
- 出版社/メーカー: 北京語言大学出版社
- 発売日: 2010/09/01
- メディア: ペーパーバック
- 購入: 2人 クリック: 4回
- この商品を含むブログを見る
21天征服新HSK6級写作(中国語) (外研社新HSK課堂系列)
- 作者: 鄭麗傑,劉悦,第1週:漢語書写基礎訓練(正確な文の表現方法など)、第2週:縮写基礎訓練(新HSK6級作文の作成方法)、第3週:縮写技巧強化訓練(叙述簡要・完備)という、3週間の学習を設定。
- 出版社/メーカー: 外語教学與研究出版社
- 発売日: 2010/05/01
- メディア: ペーパーバック
- 購入: 2人 クリック: 7回
- この商品を含むブログを見る
注:私は言語学者でもなく、単なる一中国語学習者です。おそらく中国語学習クラスタ界隈で「当たり前」となっている事と真逆なことを書いたりしているかも知れません。でも、目くじら立てて批判しないでくださいね。あくまで目的は、自分の持っているデータで何か面白いことが引き出せないか、ということなので。
あ、確率の話か (中国語の声調を推測してみる) その1
今から一ヶ月ぐらい前に、自分の持っている中国語単語DB(5800語ぐらい入っているはず)のデータをいじった話を記事にしました。
Accessing Chinese word database
Analysing Chinese words 2
Pick up combination of Pingyin and Chinese characters
この単語DBの大半(5000/5800)は、国際的な中国語試験であるHSK(汉语水平考试)の最高級である6級の試験要綱に載っていた単語なので、中国語を第2言語として勉強する人はこのぐらいのレベルに到達してねという意味において、妥当な語彙がカバーされていると言えると思います。その単語と発音(ピンイン)を抽出して、いろいろいじってみたのですが、その後一ヶ月、あまり活用されることなく放置されていました。
ところが、これまた最近放置気味だったEvernoteの整理をしている際に、当時作ったデータも取り込んでおこうかと見直したところ、意外に良い情報が転がっている(かもしれない)!と気づいたのでした。
日本人中国語学習者にとって最大の難関は声調
異論はあると思いますが、自分自身で中国語を勉強してきた実感から言わせてもらうと、日本人にとって最大の難関は声調を覚えることです。例えば初めて見る(中国語の)漢字に遭遇した時、(日本語の)音読みの傾向からピンインを想像することは、ある程度学習時間を積み上げれば、あまり難しくありません。ただ、それを声に出そうとしたときに難関となるのが声調です。発音自体は正しい(という言い方も変だけど)のに声調を誤ったがために、意思疎通できなくて悔しい思いをしたというのは一度や二度ではありません。
てか、今でもあります(笑)
じゃ、ネイティブである中国人は全ての発音を声調記号付きで覚えているのか?というとそうでもなさそうです。というのも、自分は"対外上級中国語老師"のライセンスを持っている先生に週一回中国語のレッスンを受けているのですが、発音を確認するときは、まず自分で口に出して発音してから「これは第○声」ですねという答え方をします。日本人も日本語になんとなくアクセントを付けているように、中国人も同じようにこの漢字だったら、こういう発音(声調)だという覚え方をしていると想像できます。
でも、大半の外国人中国語学習者は、いい大人になってから中国語を勉強し始めるのに、そこからネイティブな身の語彙の蓄積ができるまでにどれだけの時間を費やさないと行けないかと考えたら気が遠くなります。
人格を否定される?
ところで、音自体は正しいのに間違えた声調で発音したときに、ネイティブ中国語スピーカーの反応は想像を絶するものがあります。
んあ?
と、初めて聞いた人なら全人格を否定されたような衝撃を受けるぐらいの反応なんですが、冷静に考えると、そのネイティブさんのボキャにない発音を見舞ってしまっているので、ネイティブさんも反応に困っているわけです。
話が良い感じにこんがらがってきましたが、言いたいのは、声調だけ間違えただけにも関わらず、初めて聞いた音のようなリアクションをするネイティブさんを見るに付け、こんな仮説が思い浮かんだのです。
特定の音に対して声調に偏りがあるんじゃないか?
それなら調べてみましょう。
ということで、その2に続く。
- 作者: 株式会社スプリックス,国家漢弁/孔子学院総部
- 出版社/メーカー: スプリックス
- 発売日: 2012/02/11
- メディア: 単行本(ソフトカバー)
- 購入: 1人 クリック: 4回
- この商品を含むブログを見る
- 作者: 王素梅,新漢語水平考試の筆記模擬試験問題10セット収録。6級は語彙量5000語以上の常用詞語を把握し、中国語の情報をスムーズに読んだり聞いたりすることができ、会話や文章により、自分の見解を流暢に表現することができるレベル。
- 出版社/メーカー: 北京語言大学出版社
- 発売日: 2010/09/01
- メディア: ペーパーバック
- 購入: 2人 クリック: 4回
- この商品を含むブログを見る
21天征服新HSK6級写作(中国語) (外研社新HSK課堂系列)
- 作者: 鄭麗傑,劉悦,第1週:漢語書写基礎訓練(正確な文の表現方法など)、第2週:縮写基礎訓練(新HSK6級作文の作成方法)、第3週:縮写技巧強化訓練(叙述簡要・完備)という、3週間の学習を設定。
- 出版社/メーカー: 外語教学與研究出版社
- 発売日: 2010/05/01
- メディア: ペーパーバック
- 購入: 2人 クリック: 7回
- この商品を含むブログを見る
注:私は言語学者でもなく、単なる一中国語学習者です。おそらく中国語学習クラスタ界隈で「当たり前」となっている事と真逆なことを書いたりしているかも知れません。でも、目くじら立てて批判しないでくださいね。あくまで目的は、自分の持っているデータで何か面白いことが引き出せないか、ということなので。
Evaluation (6.3)
The Test Set (6.3.1)
>>> import random >>> from nltk.corpus import brown >>> tagged_sents = list(brown.tagged_sents(categories='news')) >>> random.shuffle(tagged_sents) >>> size = int(len(tagged_sents) * 0.1) >>> train_set, test_set = tagged_sents[size:], tagged_sents[:size]
The problem of this one is that train_set and test_set are too close. In other words, too similar. If the sentences from a same document exist both in train_set and test_set, we cannot tell the evaluation result is reasonable.
Therefore better to make sure train_set and test_set should be taken from different documents.
>>> file_ids = brown.fileids(categories='news') >>> size = int(len(file_ids) * 0.1) >>> train_set = brown.tagged_sents(file_ids[size:]) >>> test_set = brown.tagged_sents(file_ids[:size])
Another example in the text book is to extract from other categories.
>>> train_set = brown.tagged_sents(categories='news') >>> test_set = brown.tagged_sents(categories='fiction')
In my impression, this works only when creating not-category specific features.
Accuracy (6.3.2)
>>> classifier = nltk.NaiveBayesClassifier.train(train_set) .... >>> print 'Accuracy: %4.2f' % nltk.classify.accuracy(classifier, test_set) ....
Already tried Accuracy in previous sections.
Confusion Matrices (6.3.4)
>>> def tag_list(tagged_sents): ... return [tag for sent in tagged_sents for (word, tag) in sent] ... >>> def apply_tagger(tagger, corpus): ... return [tagger.tag(nltk.tag.untag(sent)) for sent in corpus] ... >>> gold = tag_list(brown.tagged_sents(categories='editorial'))
Define t2 (from section 5.4 Unigram tagger) here.
>>> t2 = nltk.UnigramTagger(brown.tagged_sents(categories='editorial')) >>> test = tag_list(apply_tagger(t2, brown.tagged_sents(categories='editorial'))) >>> cm = nltk.ConfusionMatrix(gold, test) >>> cm <ConfusionMatrix: 57382/61604 correct>
As extremely huge matrix was displayed, adjust a little bit.
>>> gold = tag_list(brown.tagged_sents(categories='editorial', simplify_tags=True)) >>> t2 = nltk.UnigramTagger(brown.tagged_sents(categories='editorial', simplify_tags=True)) >>> test = tag_list(apply_tagger(t2, brown.tagged_sents(categories='editorial'))) >>> cm = nltk.ConfusionMatrix(gold, test) >>> print cm | V | | B | | + | | A A C D M N P P V | | ' D D N E E F O N U R T U P B V V V W ` | | ' ' ( ) * , . : J V J T X W D N P M P O O H V O Z D G N H ` | -------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | <192> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . | ' | . <19> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . | '' | . . <382> . . . . . . . . . . . . . . . . . . . . . . . . . . . . | ( | . . . <95> . . . . . . . . . . . . . . . . . . . . . . . . . . . | ) | . . . . <95> . . . . . . . . . . . . . . . . . . . . . . . . . . | * | . . . . . <307> . . . . . . . . . . . . . . . . . . . . . . . . . | , | . . . . . . <2766> . . . . . . . . . . . . . . . . . . . . . . . . | . | . . . . . . . <3001> 8 . . . . . . . . . . . . . . . . . . . . . . | : | . . . . . . . . <145> . . . . . . . . . . . . . . . . . . . . . . | ADJ | . . . . . . . . . <4105> 17 1 20 . . . 64 17 . 1 . . . 5 . . . 1 4 . . | ADV | . . . . . . . . . 51 <1800> 19 104 23 . . . . 14 94 . . 1 . . . . . . 2 . | CNJ | . . . . . . . . . . 19 <2971> 17 . . . . . . 52 . . . . . . . . . . . | DET | . . . . . . . . . 21 87 162 <7365> . . . 5 . . 7 1 . . . . . . . . 9 . | EX | . . . . . . . . . . . . . <101> . . . . . . . . . . . . . . . . . | FW | . . . . . . . . . . . . . . <43> . . 1 . . . . . . . . . . . . . | MOD | . . . . . . . . . . . . . . . <933> . 1 . . . . . 1 . . . . . . . | N | . . . . . . . . . 111 11 2 2 . . 9<12065> 17 . 4 . . . 172 . 37 1 38 6 . . | NP | . . . . . . . . 1 33 . . 2 . 1 . 10 <2539> . . . . . . . . . . . . . | NUM | . . . . . . . . . . . . . . . . . . <835> . . . . . . . . . . . . | P | . . . . . . . . . . 44 76 4 . . . 1 . . <5679> . 612 . . . . . . . . . | PRO | . . . . . . . . . . . . . . . . . . 23 . <2927> . . . . . . . . . . | TO | . . . . . . . . . . . . . . . . . . . 12 . <942> . . . . . . . . . | UH | . . . . . . . . . . . . . . . . . . . . . . <8> 3 . . . . . 1 . | V | . . . . . . . . . 22 3 19 5 . . 2 213 . . . . . . <4935> . . 1 . 1 . . | VB+PPO | . . . . . . . . . . . . . . . . . . . . . . . . <1> . . . . . . | VBZ | . . . . . . . . . . . . . . . . 27 . . . . . . . . <537> . . . . . | VD | . . . . . . . . . . . . . . . . 2 . . . . . . 8 . . <470> . 221 . . | VG | . . . . . . . . . . . . . . . . 24 . . 2 . . . . . . . <880> . . . | VN | . . . . . . . . . . . . . . . . 7 . . . . . . 29 . . 71 . <1481> . . | WH | . . . . . . . . . . . 97 . . . . . . . . . . . . . . . . . <773> . | `` | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . <396>| -------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ (row = reference; col = test)
I don't know why only 9 tags are selected in the textbook's sample.
Recoginzing Textual Entailment (6.2.3)
Recognizing Textual Entailment (6.2.3)
Save as rte_features.py with following source code.
import nltk def rte_features(rtepair): extractor = nltk.RTEFeatureExtactor(rtpair) features = {} features['word_overlap'] = len(extractor.overlap('word')) features['word_hyp_extra'] = len(extractor.hyp_extra('word')) features['ne_overlap'] = len(extractor.overlap('ne')) features['ne_hype_extra'] = len(extractor.hyp_extra('ne')) return features
Then analyze the sample in the text book. Need to understand step by step.
>>> import rte_features >>> repair = nltk.corpus.rte.pairs(['rte3_dev.xml'])[33] >>> extractor = nltk.RTEFeatureExtractor(repair) >>> print extractor.text_words set(['Russia', 'Organisation', 'Shanghai', 'Asia', 'four', 'at', 'operation', 'SCO', 'Iran', 'Soviet', 'Davudi', 'fight', 'China', 'association', 'fledgling', 'terrorism', 'was', 'that', 'republics', 'Co', 'representing', 'former', 'Parviz', 'central', 'meeting', 'together', 'binds'])
This step is to extract words in the text, but 'stop words', e.g. "a" and "and", are already excluded.
>>> print extractor.hyp_words set(['member', 'SCO', 'China'])
This is the same logic but not in the text but in the hypothesis. I guess "is", "a" and "of" are in the list of the 'stop words'.
>>> print extractor.overlap('word') set([])
Nothing returned. This command should be to extract words (excluding Named Entities) in both the text and the hypothesis.
>>> print extractor.overlap('ne') set(['SCO', 'China'])
Then this one is to extract ne(=Named entities) in the both.
>>> print extractor.hyp_extra('word') set(['member'])
The last one is to extract words (excl. ne) which are only in the hypothesis.