[Python3] fastTextとgensimで自然言語処理を実装する

Gensim: 自然言語処理ライブラリ、fastTextを実行できる、トピックモデルの作成、tf-idf、Word2Vecなど
$ sudo pip3 install gensim

### 分かち書きした日本語のテキストを用意
$ wget https://s3-ap-northeast-1.amazonaws.com/dev.tech-sketch.jp/chakki/public/ja.text8.zip
$ unzip ja.text8.zip
※small (100MB) text corpus from the wikipedia
https://github.com/Hironsan/ja.text8

$ which fasttext
$ /usr/local/bin/fasttext skipgram -input ja.text8 -output ja.text8.model

一体なんやこれは?????

$ ls
app.py ja.text8 ja.text8.model.bin ja.text8.model.vec ja.text8.zip

### 学習済みモデル
$ sudo pip3 install python-Levenshtein
$ less -S ja.text8.model.vec
$ python3

>>> from gensim.models import KeyedVectors
>>> word_vecs = KeyedVectors.load_word2vec_format(‘~/test/rss/ja.text8.model.vec’, binary=False)
>>> word_vecs.most_similar(positive=[‘公園’])
[(‘東公園’, 0.7657707929611206), (‘森林公園’, 0.7654288411140442), (‘園内’, 0.7647179961204529), (‘西公園’, 0.7584214210510254), (‘レクリエーション’, 0.7228037118911743), (‘緑地公園’, 0.7194845676422119), (‘遊歩道’, 0.7175000905990601), (‘芝公園’, 0.7167261242866516), (‘グチ’, 0.7141640186309814), (‘花瀬’, 0.7108176946640015)]

>>> word_vecs.most_similar(positive=[‘国王’, ‘女’], negative=[‘男’])
[(‘王妃’, 0.6794450879096985), (‘アルフォンソ’, 0.677681028842926), (‘王族’, 0.6705313324928284), (‘テオドラ’, 0.6641644239425659), (‘アフォンソ’, 0.6623624563217163), (‘エリザヴェータ’, 0.6613386273384094), (‘シャルマネセル’, 0.6583849787712097), (‘王’, 0.6572801470756531), (‘ナバラ’, 0.6571141481399536), (‘アブデュルハミト’, 0.6528143882751465)]
>>> word_vecs.most_similar(positive=[‘駅’], negative=[])
[(‘紀勢本線’, 0.829847514629364), (‘信越本線’, 0.8256024122238159), (‘南海本線’, 0.8238951563835144), (‘東上本線’, 0.8169854879379272), (‘羽越本線’, 0.8133241534233093), (‘本四備讃線’, 0.8125778436660767), (‘中央本線’, 0.8098829984664917), (‘総武本線’, 0.8089748024940491), (‘関西本線’, 0.8083009719848633), (‘日豊本線’, 0.8078861832618713)]

つまりKeyedVectorsでmost_similarで類語を検出したり、単語の計算ができる

>>> word_vecs.most_similar(positive=[‘イチロー’, ‘サッカー’], negative=[‘野球’])[(‘フェイエノールト’, 0.7010015845298767), (‘gk’, 0.6880401372909546), (‘ベンフィカ’, 0.6829041242599487), (‘アウストリア・ウィーン’, 0.6794724464416504), (‘コパ・デル・レイ’, 0.6772794127464294), (‘ガンバ’, 0.6750086545944214), (‘ゴールキーパー’, 0.6735791563987732), (‘ゴールイン’, 0.6722267866134644), (‘ネッツァー’, 0.6708939671516418), (‘ジュビロ’, 0.668694257736206)]
が、学習データによって精度に問題がある。

プロセスとしては、
1. 形態素分析
2. fasttext skipgram -input ja.text8 -output ja.text8.model で単語をベクトルに変更
3. KeyedVectorsで学習済み日本語モデルを読み込んで使用

重み付けとは要するに多数決の理論
機械学習だとどうしてもデータセットが適切か、データ量は十分か、果たしてそのモデルが優れているのか?など、品質を上げる為には自問自答が続く。
そして、ある課題に対し、どのモデルが最適かを提案するには、モデルの構造に関する知識が不可欠であり、特徴を整理しなければならない。
突き詰めると、前頭葉を中心とした人間の脳の機能を理解して、人間が行なっている判断に類するものをモデルに反映させる
文章を読むだけでは理解できない、実際に応用して初めて物になる。

言い換えが必要なシーンを考えるか。考えることが違うな。

[Python3] fastTextでカテゴリ別に分類したい

単語のベクトル化と文章分類は、fastTextのライブラリで実装する。

$ cat /etc/redhat-release
CentOS Linux release 8.3.2011

### fastTextの利用方法
Word representation learning(単語表現学習), Text classification(文章分類)

1.Word representation learning
-> 似ている単語の学習

2.Text classification
-> 分類された文章の学習

どちらも分かち書きした文章が必要になる。
固有表現に強い辞書「mecab-ipadic-NEologd」をインストールする

$ cd /usr/local/src
$ sudo git clone –depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n -y

### fastText install
$ cd /usr/local/src
$ sudo git clone https://github.com/facebookresearch/fastText.git
$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText

$ sudo mkdir build && cd build && sudo cmake ..
$ sudo make && sudo make install
$ which fasttext
/usr/local/bin/fasttext

$ cd /usr/local/src/fastText
$ sudo pip3 install .

$ wget https://github.com/livedoor/datasets/archive/master.zip
$ ls
$ unzip master.zip
$ cd datasets-master/
$ gzip -d ldgourmet.tar.gz
$ tar xvf ldgourmet.tar
$ ls
README.md categories.csv prefs.csv ratings.csv stations.csv
areas.csv ldgourmet.tar rating_votes.csv restaurants.csv

### 前処理 & データセットの作成
app.py

import csv
import MeCab
import neologdn
import re
import emoji

mecab = MeCab.Tagger('-Owakati -d /usr/lib64/mecab/dic/mecab-ipadic-neologd/')

with open('rating.csv') as f:
	reader = csv.reader(f)
	next(reader)
	for row in reader:
		label = "__label__{0}".format(row[3])

		text1 = neologdn.normalize(row[9])
		text2 = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+','', text1)
		text3 = ''.join(['' if c in emoji.UNICODE_EMOJI else c for c in text2])
		tmp = re.sub(r'(\d)([,.])(\d+)', r'\1\3', text3)
		text4 = re.sub(r'\d+', '0', tmp)

		tmp = re.sub(r'[!-/:-@[-`{-~]', r' ', text4)
		text5 = re.sub(u'[■-♯]', '	', tmp)

		text = mecab.parse(text5).rstrip('\n')
		print(label + " , " + text)

なんやこれ、前準備が厄介やな。。。。
どうすっかな、これ。。。

[Python3] RSSフィードの取得

CentOS8で作業します。

$ python3 –version
Python 3.6.8
$ pip3 –version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)

### feedparserをインストール
$ sudo pip3 install feedparser
// 動作テスト
$ python3
Python 3.6.8 (default, Aug 24 2020, 17:57:11)
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import feedparser
>>> d = feedparser.parse(‘https://news.yahoo.co.jp/pickup/rss.xml’)
>>> d[‘feed’][‘title’]
‘Yahoo!ニュース・トピックス – 主要’

# -*- coding: utf-8 -*-
import feedparser

URL = 'https://news.yahoo.co.jp/rss/topics/top-picks.xml'

d = feedparser.parse(URL)
for entry in d.entries:
	print(entry.title, entry.link)

$ python3 app.py
山形県 独自の緊急宣言を拡大 https://news.yahoo.co.jp/pickup/6388973?source=rss
殺せない 逃げたミャンマー兵 https://news.yahoo.co.jp/pickup/6388959?source=rss
18歳刺殺 車に注意し口論か https://news.yahoo.co.jp/pickup/6388974?source=rss
兄の無実60年間信じ 妹の訴え https://news.yahoo.co.jp/pickup/6388951?source=rss
辛ラーメン開発 辛春浩氏死去 https://news.yahoo.co.jp/pickup/6388971?source=rss
楽天則本が離婚「僕に原因」 https://news.yahoo.co.jp/pickup/6388968?source=rss
元力士の漫画家 琴剣さん死去 https://news.yahoo.co.jp/pickup/6388962?source=rss
谷原章介 帯の司会頭にあった https://news.yahoo.co.jp/pickup/6388972?source=rss

RSSにMeCabを使う

# -*- coding: utf-8 -*-
import feedparser
import MeCab

wakati=MeCab.Tagger("-Owakati")
URL = 'https://news.yahoo.co.jp/rss/topics/top-picks.xml'
sentence_wakati = []

d = feedparser.parse(URL)
for entry in d.entries:
	# print(entry.title, entry.link)
	sentence = wakati.parse(entry.title).split()
	sentence_wakati.append(sentence)

print(sentence_wakati)

$ python3 app.py
[[‘ミャンマー’, ‘クーデター’, ‘正当’, ‘化’], [‘山形’, ‘県’, ‘独自’, ‘の’, ‘緊急’, ‘宣言’, ‘を’, ‘拡大’], [’18’, ‘歳’, ‘刺殺’, ‘車’, ‘に’, ‘注意’, ‘し’, ‘口論’, ‘か’], [‘聖火’, ‘リレー’, ‘初’, ‘の’, ‘週末’, ‘密集’, ‘警戒’], [‘辛’, ‘ラーメン’, ‘開発’, ‘辛’, ‘春’, ‘浩’, ‘氏’, ‘死去’], [‘楽天’, ‘則’, ‘本’, ‘が’, ‘離婚’, ‘「’, ‘僕’, ‘に’, ‘原因’, ‘」’], [‘東海’, ‘大’, ‘菅生’, ‘が’, ‘サヨナラ’, ‘初’, ‘8’, ‘強’], [‘谷原’, ‘章介’, ‘帯’, ‘の’, ‘司会’, ‘頭’, ‘に’, ‘あっ’, ‘た’]]

RSSテキストのカテゴリ分けをやりたい。

[PHPQuery]プロキシ経由でスクレイピングする

無料プロキシリストからproxyを取得してスクレピングする。
http://www.freeproxylists.net/ja/?c=JP&pt=&pr=&a%5B%5D=0&a%5B%5D=1&a%5B%5D=2&u=0

$url = "https://www.google.com/";
// $proxy_url = "153.126.160.91:80";
$proxy_url = "133.167.65.45:8080";

$context = stream_context_create(array(
      'http' => array(
         'method' => 'GET',
         'header'=>'User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/00100101 Firefox/13.0.1\r\nReferer: https://www.google.com/webhp?gl=us&hl=en&gws_rd=cr&pws=0',
         'ignore_errors'=>true,
         'proxy' => $proxy_url,
      )
   ));
$html = file_get_contents($url, FALSE, $context);
$doc = phpQuery::newDocument(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));


echo $doc["title"]->text();

$ php test.php
Google

設定するプロキシによっては、接続を拒否される場合があるので、テストして確認が必要
Cannot connect to HTTPS server through proxy in /home/vagrant/test/test.php on line 17

なるほどー凄い理解した^^

vagrantでプロキシサーバを使用したい

VagrantのゲストOSにProxy設定を行うには、vagrant-proxyconfを使う。plug-inのインストールが必要

$ vagrant plugin install vagrant-proxyconf
$ vagrant plugin list
vagrant-proxyconf (2.0.10, global)
vagrant-vbguest (0.20.0, global)

### focalfossa
vagrantのubuntu/focal64を使いたいと思う
$ vagrant init ubuntu/focal64

公開プロキシのサイトを検索します

とりあえず、最初なので日本のプロキシサーバを使う
http
43.248.24.158 51166
https
133.167.65.45 8080

Vagrantfile

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"
  config.vm.network "private_network", ip: "192.168.33.10"

  if Vagrant.has_plugin?("vagrant-vbguest")
      config.vbguest.auto_update = false  
  end

  if Vagrant.has_plugin?("vagrant-proxyconf")
    config.proxy.http = "http://43.248.24.158:51166/"
    config.proxy.https = "http://133.167.65.45:8080/"
    config.proxy.no_proxy = "localhost,127.0.0.1,192.168.33.10"
  end
end

$ vagrant up

$ printenv http_proxy https_proxy
http://43.248.24.158:51166/
http://133.167.65.45:8080/

なるほど、proxyについて完全に理解した🔥

プロキシサーバーとは

プロキシサーバとは、内部ネットワークとインターネットの境界で動作し、両者間のアクセスを代理するもの
キャッシュ機能がある
– キャッシュ、ユーザー認証、フィルタリング、ウィルス対策、匿名性確保

### プロキシサーバのメリット
– プロキシ上にログが残る
– プロキシサーバを経由すると、端末のIPが相手に残らない

### 注意点
– 公開プロキシは個人情報を抜き取るものもあるため、個人情報を扱う場合は、公開プロキシは使用しない

リバースプロキシとは、外部インターネットからサーバーへアクセスされる通信を中継する仕組み

なるほど、仕組みは理解したが、使ってみないとわからんな。

自然言語処理のアプリケーションを考える

自然言語処理を用いたサービスを検討する。国内で最も見かけるのはチャットボットの開発だが、チャットボット自体は、ホテルのHPなどで頻繁に見かけるが、問い合わせとして自分自身が使おうと思わないので、それを開発したいと思うモチベーションがイマイチ湧いてこない。
自然言語処理というと形態素解析を真っ先に思い浮かべるが、企業内でのニーズは、社内文章の検索やカテゴライズといったもので、営業秘密もあるだろうから、中々表に出て来にくいし、それ自体も人が管理できることなので、あまりニーズがあるとは考えられない。
文章を使う業界、すなわち出版業界での校閲を自動化というのも考えたが、それにニーズがあるともあまり思わない。
学習なら、RSS, Twitterが無難そうだが、Twitterは過去作ったことがある。
業界ニーズに特化した

### 法人全般サービス
ホームページ:チャットボット、問い合わせ回答
営業:見込み客の抽出
R&D:メディア記事解析、検索エンジン
社内文章:カテゴライズを自動化、文章構造化、文章の極性判定、検索エンジン、帳票からの抽出

### 業界のサービス
コールセンター:対応評価、会話ログのマイニング、音声認識
広告:校正校閲審査
工事:類似する施工計画書を検索
法務サービス

### 個人サービス
SNS:Twitter/instagram:感情情報、投稿内容分析、特定のキーワードを見つける
RSS:カテゴライズを自動化、文章構造化

### Google, Amazon, Facebook, Microsoft
翻訳
検索

う〜む、音声認識もやりたいな。
まずはRSSから攻めるか

Pythonで自然言語処理(mecab)

$ python3 –version
Python 3.6.8
$ pip3 –version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)

$ sudo pip3 install mecab-python3
$ sudo pip3 install unidic-lite

単語と単語を分けるのを分かち書きという
$ python3
>>> import MeCab
>>> wakati=MeCab.Tagger(“-Owakati”)
>>> sentence_wakati = wakati.parse(“私は今システム開発を行なっています”).split()
>>> print(sentence_wakati)
[‘私’, ‘は’, ‘今’, ‘システム’, ‘開発’, ‘を’, ‘行なっ’, ‘て’, ‘い’, ‘ます’]

ん?
“行なって” + “います” が正の様に思うが。。

自然言語処理ってことは、検索エンジン周りかチャットボット関連か。
もしくは文章の中から特定のキーワードを見つける e.g. 技術トレンドが入っている用語
RSSから、自然言語処理で内容を評価して、カテゴライズを自動化する など

何をやるかやな。

D4を更に理解しよう

ORDA: Object Relational Data Access

Table, field, and relation names are mapped to object property names. Make sure that such names comply with general object naming rules, as explained in the object naming conventions section.
A datastore only references tables with a single primary key. The following tables are not referenced:
Tables without a primary key
Tables with composite primary keys.
BLOB type attributes are not managed in the datastore. BLOB type attributes are returned as Null in entities and cannot be assigned.

$mydatastore:=OB Copy(ds) 
 ARRAY TEXT($prop;0)
 OB GET PROPERTY NAMES(ds;$prop)

こりゃハードル高いというか、時間がかかるな。。

D4を使ってみよう

4D Product DownloadのページからDLします。
https://us.4d.com/product-download/Feature-Release

4D Documentationを見ながらやっていきます。

Projectを作ります。

Architecture of project
– components
– data
L logs
L settings
– documentation
– plugins
– project
L derivedData
L sources
L trash
– resources
– settings
– userPreferences.username
– WebFolder

Project folder
– sources
L classes, databaseMethods, Methods, Forms, TableForms, Triggers
– DerivedData
– Trash

${appname}.4DProject: 4D, 4D server

設定ファイルはXMLやJSONで書かれてますね。
メソッドを作って、ドキュメントを書く。

<!-- This method returns a different logo depending on the size parameter -->


GetLogo (size) -> logo


| Parameter | Type   | in/out | Description |
| --------- | ------ | ------ | ----------- |
| size      | Longint | in | Logo style selector (1 to 5)  |
| logo      | Picture | out | Selected logo |


## Description

This method returns a logo of a specific size, depending on the value of the *size* parameter value.
1 = smallest size, 5 = largest size.

## Example

C_PICTURE($logo)
C_LONGINT($size)

//Get the largest logo
$logo:=GetLogo(5)

ちょっとだけ理解した。