Pythonで英文のデータセットを使ってTextClassificationをしたい1

#### choosing a Data Set
Sentiment Labelled Sentences Data Set
https://archive.ics.uci.edu/ml/machine-learning-databases/00331/

※Yelpはビジネスレビューサイト(食べログのようなもの)
※imdbは映画、テレビなどのレビューサイト

こちらから、英文のポジティブ、ネガティブのデータセットを取得します。
$ ls
amazon_cells_labelled.txt imdb_labelled.txt readme.txt yelp_labelled.txt

import pandas as pd 

filepath_dict = {
	'yelp': 'data/yelp_labelled.txt',
	'amazon': 'data/amazon_cells_labelled.txt',
	'imdb': 'data/imdb_labelled.txt'
}

df_list = []
for source, filepath in filepath_dict.items():
	df = pd.read_csv(filepath, names=['sentence', 'label'], sep='\t')
	df['source'] = source
	df_list.append(df)

df = pd.concat(df_list)
print(df.iloc[0])

$ python3 app.py
sentence Wow… Loved this place.
label 1
source yelp
Name: 0, dtype: object

This data, predict sentiment of sentence.
vocabularyごとにベクトル化して重みを学習して判定する
>>> sentences = [‘John likes ice cream’, ‘John hates chocolate.’]
>>> from sklearn.feature_extraction.text import CountVectorizer
>>> vectorizer = CountVectorizer(min_df=0, lowercase=False)
>>> vectorizer.fit(sentences)
CountVectorizer(lowercase=False, min_df=0)
>>> vectorizer.vocabulary_
{‘John’: 0, ‘likes’: 5, ‘ice’: 4, ‘cream’: 2, ‘hates’: 3, ‘chocolate’: 1}
>>> vectorizer.transform(sentences).toarray()
array([[1, 0, 1, 0, 1, 1],
[1, 1, 0, 1, 0, 0]])

### Defining Baseline Model
First, split the data into a training and testing set

from sklearn.model_selection import train_test_split
import pandas as pd 

filepath_dict = {
	'yelp': 'data/yelp_labelled.txt',
	'amazon': 'data/amazon_cells_labelled.txt',
	'imdb': 'data/imdb_labelled.txt'
}

df_list = []
for source, filepath in filepath_dict.items():
	df = pd.read_csv(filepath, names=['sentence', 'label'], sep='\t')
	df['source'] = source
	df_list.append(df)

df = pd.concat(df_list)

df_yelp = df[df['source'] == 'yelp']
sentences = df_yelp['sentence'].values
y = df_yelp['label'].values

sentences_train, sentences_test, y_train, y_test = train_test_split(
	sentences, y, test_size=0.25, random_state=1000)

.value return NumPy array

from sklearn.feature_extraction.text import CountVectorizer

// 省略

sentences_train, sentences_test, y_train, y_test = train_test_split(
	sentences, y, test_size=0.25, random_state=1000)

vectorizer = CountVectorizer()
vectorizer.fit(sentences_train)

X_train = vectorizer.transform(sentences_train)
X_test = vectorizer.transform(sentences_test)
print(X_train)

$ python3 split.py
(0, 125) 1
(0, 145) 1
(0, 201) 1
(0, 597) 1
(0, 600) 1
(0, 710) 1
(0, 801) 2
(0, 888) 1
(0, 973) 1
(0, 1042) 1
(0, 1308) 1
(0, 1345) 1
(0, 1360) 1
(0, 1494) 2
(0, 1524) 2
(0, 1587) 1
(0, 1622) 1
(0, 1634) 1
(1, 63) 1
(1, 136) 1
(1, 597) 1
(1, 616) 1
(1, 638) 1
(1, 725) 1
(1, 1001) 1
: :
(746, 1634) 1
(747, 42) 1
(747, 654) 1
(747, 1193) 2
(747, 1237) 1
(747, 1494) 1
(747, 1520) 1
(748, 600) 1
(748, 654) 1
(748, 954) 1
(748, 1001) 1
(748, 1494) 1
(749, 14) 1
(749, 15) 1
(749, 57) 1
(749, 108) 1
(749, 347) 1
(749, 553) 1
(749, 675) 1
(749, 758) 1
(749, 801) 1
(749, 1010) 1
(749, 1105) 1
(749, 1492) 1
(749, 1634) 2

#### LogisticRegression

from sklearn.linear_model import LogisticRegression

classifier = LogisticRegression()
classifier.fit(X_train, y_train)
score = classifier.score(X_test, y_test)

print("Accuracy:", score)

$ python3 split.py
Accuracy: 0.796

for source in df['source'].unique():
	df_source = df[df['source'] == source]
	sentences = df_source['sentence'].values
	y = df_source['label'].values

	sentences_train, sentences_test, y_train, y_test = train_test_split(
		sentences, y, test_size=0.25, random_state=1000)

	vectorizer = CountVectorizer()
	vectorizer.fit(sentences_train)
	X_train = vectorizer.transform(sentences_train)
	X_test = vectorizer.transform(sentences_test)

	classifier = LogisticRegression()
	classifier.fit(X_train, y_train)
	score = classifier.score(X_test, y_test)
	print('Accuracy for {} data: {:.4f}'.format(source, score))

$ python3 split.py
Accuracy for yelp data: 0.7960
Accuracy for amazon data: 0.7960
Accuracy for imdb data: 0.7487

[python3] フォームのデータを受信し表示

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<h1>翻訳したい言語を入力してください</h1>
	<form method="POST" action="result.py">
		<label>テキスト:</label>
		<textarea name="text"></textarea>
		<button type="submit">送信</button>
	</form>
</body>
</html>

result.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import cgi
import cgitb
import sys

cgitb.enable()

form = cgi.FieldStorage()

print("Content-Type: text/html; charset=UTF-8")
print("")

if "text" not in form:
	print("<h1>Erro!</h1>")
	print("<br>")
	print("テキストを入力してください!")
	print("<a href='/'><button type='submit'>戻る</button></a>")
	sys.exit()

text = form.getvalue("text")
print(text)

ん。。。なんか上手くいかんな。

[python3] googletransで日本語->英語に翻訳する

$ sudo pip3 install googletrans
Successfully installed chardet-3.0.4 contextvars-2.4 googletrans-3.0.0 h11-0.9.0 h2-3.2.0 hpack-3.0.0 hstspreload-2020.12.22 httpcore-0.9.1 httpx-0.13.3 hyperframe-5.2.0 immutables-0.15 rfc3986-1.4.0 sniffio-1.2.0

# -*- coding: utf-8 -*-
from googletrans import Translator
translator = Translator()

translation = translator.translate("こんにちは", src='ja', dest="en")
print(translation.text)

$ python3 app.py
AttributeError: ‘NoneType’ object has no attribute ‘group’

どうやら3.0.0ではなく、4系が動いているとのこと
$ sudo pip3 uninstall googletrans
$ sudo pip3 install googletrans==4.0.0-rc1

# -*- coding: utf-8 -*-
from googletrans import Translator
translator = Translator()

translation = translator.translate("h音楽アーティストやレコードレーベルが保有する楽曲を NFT 化し世界中に販売", src='ja', dest='en')
print(translation.text)

$ python3 app.py
Music artists and songs owned by record labels NFT and sell worldwide

なかなか凄いな
formからpostして翻訳して返却したいな

[python3] twitterのつぶやきからmecabとwordcloudで解析する

# -*- coding: utf-8 -*-
import MeCab
import matplotlib.pyplot as plt
import csv
from wordcloud import WordCloud

dfile = "test.txt"

fname = r"'" + dfile + "'"
fname = fname.replace("'","")

mecab = MeCab.Tagger("-Owakati")

words = []

with open(fname, 'r', encoding="utf-8") as f:

	reader = f.readline()

	while reader:

		node = mecab.parseToNode(reader)

		while node:
			word_type = node.feature.split(",")[0]

			if word_type in ["名詞", "動詞", "形容詞", "副詞"]:

				words.append(node.surface)

			node = node.next

		reader = f.readline()

font_path = "NotoSansMonoCJKjp-Regular.otf"

txt = "	".join(words)

stop_words = ['そう', 'ない', 'いる', 'する', 'まま', 'よう', 'てる', 'なる', 'こと', 'もう', 'いい', 'ある', 'ゆく', 'れる', 'ん', 'の']

wordcloud = WordCloud(background_color="black", font_path=font_path, stopwords=set(stop_words),
	width=800, height=600).generate(txt)

wordcloud.to_file('./wordcloud.png')

なるほど、一応できたか
キーワードを自然言語処理ではなく、「自民 -RT」でstop_wordsに自民を指定してやってみる

政党名が多くて、ちょっと期待してたのと違うな。。。

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

beautifulsoupでUserAgentとProxyを設定する

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
from pprint import pprint

URL = 'https://news.yahoo.co.jp/'
USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"

proxies = {
	'http':'http://43.248.24.158:51166/',
	'https':'http://43.128.23.107:8080/'
}
headers = {"User-Agent": USER_AGENT}

resp = requests.get(URL, proxies=proxies, headers=headers, timeout=10)
resp.encoding = 'utf8' 
soup = BeautifulSoup(resp.text, "html.parser")

titles = soup.select('.sc-esjQYD a')
titles = [t.contents[0] for t in titles]

pprint(titles)

$ python3 app.py
[‘春の嵐 太平洋側激しい雷雨も’,
‘コロナワクチン種類選択OKに’,
‘北ミサイル 安保理緊急協議へ’,
‘生息域40年で倍 減らぬシカ’,
‘中国の謎の文明 黄金仮面発見’,
‘羽生まるで別人 専門家の目’,
‘みちょぱ 結婚の話している’,
‘水卜アナ 局アナ続ける理由’]

なるほど、BSでも行けますね、OK

[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テキストのカテゴリ分けをやりたい。

ubuntu bionicでpython3のcronを設定する

まず実行したいpyファイルを用意します。
/home/vagrant/local/cron/app.py

$ crontab -l
no crontab for vagrant
$ crontab -e

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 2

$ which python
/usr/bin/python

$ crontab -e

*/5 * * * * /usr/bin/python /home/vagrant/local/cron/app.py

// cronリスタート
$ /etc/init.d/cron restart
// 実行ログの確認
$ sudo journalctl -f -u cron

実行テストは、5分おき(*/5 * * * *)ではなく、1分おきの方が良いですね。
続いて、raspberry pi4でcronを設定します。

[Python 3.8.0] S3に画像をアップロード・ダウンロードする

### S3へupload
1.まず送信したい画像を用意します。SVMで使用したgeorgia.jpgを使いましょう。

2.AWSコンソールにログインし、S3からbucketを作成します。
取り敢えず、hanbai-raspi としておきます。

画像の送受信のみに利用する為、Block all public accessにします。

3.AmazonS3FullAccessのユーザを作成

4.ubuntu側でAWS SDKのboto3をインストール
$ pip -V
pip 20.1.1 from /home/vagrant/.local/lib/python3.8/site-packages/pip (python 3.8)
$ pip install boto3

import boto3

accesskey = "****"
secretkey = "****"
region = "ap-northeast-1"

s3 = boto3.client('s3', aws_access_key_id=accesskey, aws_secret_access_key= secretkey, region_name=region)

filename = "georgia.jpg"
bucket_name = "hanbai-raspi"

s3.upload_file(filename,bucket_name,filename)
print("upload {0}".format(filename))

$ python app.py
upload georgia.jpg

はい、アップロードできてます。

続いて、downloadもやっちゃいましょう。

### download

import boto3

accesskey = "****"
secretkey = "****"
region = "ap-northeast-1"

s3 = boto3.resource('s3', aws_access_key_id=accesskey, aws_secret_access_key= secretkey, region_name=region)

bucket = s3.Bucket("hanbai-raspi")
filename="georgia.jpg"
path="img/georgia.jpg"


bucket.download_file(filename,path)
print("upload {0}".format(filename))

アップロードとダウンロードだと書き方が若干異なるので注意が必要ですね。
さあ、続いて、ubuntuとラズパイ4でcronの実行の仕方。

Pythonでqrコードを作りたい

QRコード画像生成ライブラリ「qrcode」をインストールします。

$ pip install qrcode
$ pip install pillow

### テキストを画像にする

import qrcode

qr = qrcode.QRCode()
qr.add_data('test text')
qr.make()
img = qr.make_image()
img.save('qrcode.png')

### URLを画像にする

import qrcode

qr = qrcode.QRCode()
qr.add_data('https://www.google.com/')
qr.make()
img = qr.make_image()
img.save('qrcode.png')

アラ? 凄い簡単に出来ますね。。。簡単過ぎてビックリした。

Python & reportlab でPDF見積書を作成

pythonでPDFの見積書を作っていきます。
reportlabでテーブルではなくテキスト配置で右寄せがわからないのが脛に傷。

# -*- coding: utf-8 -*-

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.lib.pagesizes import A4, portrait
from reportlab.platypus import Table, TableStyle
from reportlab.lib.units import mm
from reportlab.lib import colors


def make(filename="estimate"): # ファイル名
    pdf_canvas = set_info(filename) # キャンバス名
    print_string(pdf_canvas)
    pdf_canvas.save() # 保存

def set_info(filename):
	pdf_canvas = canvas.Canvas("./{0}.pdf".format(filename))
	pdf_canvas.setAuthor("hpscript")
	pdf_canvas.setTitle("見積書")
	pdf_canvas.setSubject("見積書")
	return pdf_canvas

def print_string(pdf_canvas):
	# フォント登録
	pdfmetrics.registerFont(UnicodeCIDFont('HeiseiKakuGo-W5'))

	width, height = A4

	# 見積日
	font_size = 9
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(440, 810, '見積日: 2020年10月1日')

	# title
	font_size = 24
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(245, 770, '御 見 積 書')

	# 線
	pdf_canvas.line(50, 750, 550, 750)

	# 宛先
	font_size = 14
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(60, 710, '六本木ソフトウェア株式会社 御中')
	pdf_canvas.drawString(60, 690, '営業部  山田太郎 様')

	# 線
	pdf_canvas.line(50, 680, 350, 680)

	# 注釈
	font_size = 9
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(190, 670, '下記の通りお見積もり申し上げます。')

	# 納期、支払条件、有効期限
	font_size = 12
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(100, 635, '納期:')
	pdf_canvas.drawString(200, 635, '別途ご相談')
	pdf_canvas.line(200, 633, 350, 633)

	pdf_canvas.drawString(100, 615, '支払い条件:')
	pdf_canvas.drawString(200, 615, '月末締め翌月末払い')
	pdf_canvas.line(200, 612, 350, 612)

	pdf_canvas.drawString(100, 595, '有効期限:')
	pdf_canvas.drawString(200, 595, 'お見積り後2週間')
	pdf_canvas.line(200, 593, 350, 593)

	# 自社情報
	font_size = 9
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(360, 680, '丸の内ソフトウェア株式会社')
	pdf_canvas.drawString(360, 670, '〒100-0001')
	pdf_canvas.drawString(360, 660, '東京都千代田区千代田1-1-1')
	pdf_canvas.drawString(360, 645, 'TEL: 03-1234-5678')
	pdf_canvas.drawString(360, 635, 'E-mail: info@marunouchi-soft.com')
	pdf_canvas.drawString(360, 625, '担当: 田中一郎')

	# 合計金額
	font_size = 14
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(80, 550, '合計金額')
	pdf_canvas.drawString(180, 550, '800,000 円 (税込)')

	# 線
	pdf_canvas.line(50, 540, 350, 538)

	# 分類、型番、品名、規格寸法、基準単価
	data = [
		['分類', '型番','品名', '規格寸法','数量','基準単価'],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
		[' ',' ',' ',' ',' '],
	]
	table = Table(data, colWidths=(25*mm, 25*mm, 55*mm, 25*mm, 15*mm,30*mm), rowHeights=7.5*mm)
	table.setStyle(TableStyle([
			('FONT', (0, 0), (-1, -1), 'HeiseiKakuGo-W5', 8),
			('BOX', (0, 0), (-1, -1), 1, colors.black),
			('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
			('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
		]))
	# table.wrapOn(pdf_canvas, 20*mm, 20*mm)
	table.wrapOn(pdf_canvas, 20*mm, 20*mm)
	table.drawOn(pdf_canvas, 18*mm, 100*mm)

	# 小計、消費税、合計
	font_size = 9
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(360, 250, '小計:')
	pdf_canvas.drawString(450, 250, '700000円')
	pdf_canvas.line(360, 245, 550, 245)	

	pdf_canvas.drawString(360, 230, '消費税:')
	pdf_canvas.drawString(450, 230, '70000円')
	pdf_canvas.line(360, 225, 550, 225)	

	pdf_canvas.drawString(360, 210, '合計:')
	pdf_canvas.drawString(450, 210, '770000円')
	pdf_canvas.line(360, 205, 550, 207)	

	# 宛先
	font_size = 9
	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)
	pdf_canvas.drawString(60, 175, '備考')

	pdf_canvas.rect(50, 50, 500, 120)



	pdf_canvas.showPage()
	
if __name__ == '__main__':
	make()

$ python estimate.py

OK、これをDjangoに組み込みたい。この関数はviews.pyに書くけば良いのか???