OmniAICreator/Qiita-1.07M huggingface dataset:
pythonで複数画像をPDFファイルに変換する

#はじめに
画像ファイルからpdfの作成方法といえばオンラインのフリー変換サイト[(smallpdfとか)](https://www.ilovepdf.com/ja/jpg_to_pdf)が有名ですが、アップロードサイズとか変換速度がネックです。ローカルでやれるならローカルで変換したいですね。今回使うのは[img2pdf](https://pypi.org/project/img2pdf/)というモジュールです。

参考サイト:  [Pythonを使って画像をPDFに変換する](https://qiita.com/daikan_murata/items/e1c38db8b41d141f12d8)

##準備
```
pip install img2pdf
pip install Pathlib
```
#コード
```python:ImgToPdf.py
import img2pdf
from pathlib import Path

#単処理
def ImageToPdf(outputpath, imagepath):
    '''
    outputpath: pathlib.Path()
    imagepath: pathlib.Path()
    '''
    lists = list(imagepath.glob("**/*"))#単フォルダ内を検索
    #pdfを作成
    with open(outputpath,"wb") as f:
        #jpg,pngファイルだけpdfに結合
        #Pathlib.WindowsPath()をstring型に変換しないとエラー
        f.write(img2pdf.convert([str(i) for i in lists if i.match("*.jpg") or i.match("*.png")]))
    print(outputpath.name + " :Done")

#複数フォルダをループ処理する
def main():
    #作業フォルダ
    base_path = r"your work folder path"
    #作業フォルダ内のディレクトリだけを抽出する
    glob = Path(base_path).glob("*")
    imagefolderlist = list([item for item in list(glob) if item.is_dir()])
    #outputpathに指定ディレクトリと同名を指定する
    outputpathlist = list([item.with_name(item.name + ".pdf") for item in imagefolderlist])
    #ループ処理を行う
    for outputpath,imagepath in zip(outputpathlist,imagefolderlist):
        try:
            ImageToPdf(outputpath,imagepath)
        except:
            pass
```

##ありがちな罠
パスの入力が必要な箇所にPathlib.Path()を突っ込むとエラー吐くモジュールもよくあるので,
str(Pathlib.Path())でパスをstring型に直す必要があります。
オーダー記法でlogの基数を書かない理由

アルゴリズムの効率を表現するのにオーダー記法というものが使われる。例えば「アルゴリズムAのオーダーは $O(n^2)$ だが、アルゴリズムBは $O(n\log n)$ なので B の方が効率的」みたいに言ったりする。

さて、このオーダー記法において対数 $\log$ がでてきたとき普通は基数を無視するが、それは何故か。

$\log_2$ の（基数が 2 の対数）値があるとする。これを $\log_{10}$ に変換してみよう。 $a=\log_2 k, b=\log_{10} k$ とすると $k = 10^b$ なので

```math
\log_2 (10^b) = \log_2 k \\
b \log_2 10 = \log_2 k \\
b = \frac{\log_2 k}{\log_2 10} = \frac{a}{\log_2 10}
```

$\log_2 10$ は定数なので、要するに $b$ は $a$ の定数倍ということになる。オーダー記法では定数倍は無視するので、結局オーダー記法において基数は無視されることになる。という訳。
INSERT ON DUPLICATE KEY UPDATEの利点と注意点

所属しているプロジェクトで　`INSERT ON DUPLICATE KEY UPDATE` を使っているが、問題が起きたのでまとめておく。

# 起きた問題
INSERT のときだけでなく、UPDATE の処理が走った際にも、AUTO_INCREMENT が増えてしまい、AUTO_INCREMENT で更新される値が予測を超えて増加し、int型の最大値に達してしまい、データの挿入ができなくなった。

# INSERT ON DUPLICATE KEY UPDATEとは
INSERT しようとした時に、UNIQUE インデックス または PRIMARY KEY に重複した値を発生させるレコードが挿入されていた場合は、古いレコードの UPDATE が実行されるという構文。

# 使っていた状況
例えばユーザーの獲得した様々な種類のポイントとかいろんな行動のサマリなどのように、確実にレコードがあるかどうか分からないようなテーブルに対して、「レコードがないならば挿入したいけど、レコードがあるならば更新したい」という状況で使っていた。

先にデータがあるかどうかを確認するためにロックを取りつつ SELECT を行うと、そのレコードがない場合にはギャップロックになってしまい、SELECT の条件に関係ないような多くの　INSERT もブロックされてしまう。
しかし、ロックを取らずに SELECT すると、SELECT から INSER での隙間で別のトランザクションから INSERT されてしまう可能性がある。

そのような状況下で、INSERT もしくは UPDATE がひとつの処理で行われる `INSERT ON DUPLICATE KEY UPDATE` を利用していた。

# どうすれば避けられるか？
## bigintにする
AUTO_INCREMENT によって増えるカラムの型を bigint でスキーマを定義する。
または、bigint になるように ALTER をたたく。
int(unsigned)の最大値は4294967295と約42億であるが、bigint(unsigned)の最大値は18446744073709551615と約1844京と想像できないくらいに大きな数になる。

bigintにすることで、たいていの状況では、人やプロジェクトが生きているうちには使い切れないと思えるような最大値になる。

## MySQLの設定を変える
MySQLでは、ストレージエンジンとしてInnoDBを採用している。
デフォルトでは `innodb_autoinc_lock_mode = 1` で、「連続」 ロックモードに設定されている。
この設定を `innodb_autoinc_lock_mode = 0` で、「従来」 ロックモードに設定することで、すべての 「INSERT のような」ステートメントでは、特殊なテーブルレベル AUTO-INC ロックが取得され、ステートメントの終了まで保持される。
これにより、特定のステートメントによって割り当てられた自動インクリメント値が連続的になる。

しかし、高速化のためにデフォルトが「連続」ロックモードになっているので、処理のパフォーマンスを落としてまで利用するべきなのかは分からない。

## 仕様を見直す
例えば、このプロジェクトでは、一つの行動の結果により、いろいろなタイプのポイントやサマリが更新される仕様であった。
さらに言うと同時開催されているキャンペーンの数だけ、同じだけのデータを記録する仕様であった。
つまり、一つの行動で `開催しているキャンペーン×ポイントタイプの種類` の数だけ INSERT が試され、レコードがある場合は AUTO_INCREMENT が増えるのである。
しかも使っていないようなタイプのポイントも記録していたので、無駄があったことになる。
仕様と処理を見直し、本当に必要な処理なのかどうか判断することも必要となる。（DBへのアクセスが減ると、処理時間も減るしね）

# まとめ
スキーマ定義で、AUTO_INCREMENT を設定しているものは bigint の型にしておけばとりあえず安心なのではなかろうか。

しかし、つど仕様や処理を見直して、必要であれば仕様レベルから変えて行くことで、プロジェクトとしての健康度は保っていくと思う。

# 参考
https://dev.mysql.com/doc/refman/5.6/ja/insert-on-duplicate.html
https://dev.mysql.com/doc/refman/5.6/ja/innodb-auto-increment-configurable.html
Docker環境でRedmineを立ち上げてslackと連携させてみた

今回はRedmineをこのドッカーイメージとSlackのプラグインを使用しました。
※bitnami (https://github.com/bitnami/bitnami-docker-redmine) のドッカーイメージもありますが、こちらの方があらかじめBundlerが入ってるなど運用面で便利です。

**Redmine**
 - https://github.com/sameersbn/docker-redmine
**Slack plugin**
 - https://github.com/sciyoshi/redmine-slack

### Docker imageの立ち上げ

```
$ wget https://raw.githubusercontent.com/sameersbn/docker-redmine/master/docker-compose.yml
$ docker-compose up -d
```

#### Macの場合
docker-compose.ymlでデフォルトで設定されているvolumeのファイルパスは、Mac OS Sierra以降だと権限が厳しくエラーになります。
そのため今回は、volumeの設定を以下のように変更しました。
パス指定方法は次のように書きます。
- ホスト側のパス:ドッカー側のパス

```
services:
  postgresql:
    (省略)
    volumes:
    - ./postgresql:/var/lib/postgresql
    
  redmine:
　　(省略)
    volumes:
    - ./redmine:/home/redmine/data
```

### プラグインの設置
ドッカ―コンテナ内のpluginsフォルダに入ります。

```
$ docker exec -it redmine_redmine_1 bash
# cd plugins
```

Redmine用のSlackプラグインをクローンしてきます。

```
# git clone https://github.com/sciyoshi/redmine-slack.git redmine_slack
# cd redmine_slack
```

プラグイン内のGemfileをRedmineのGemfileに移します。

```
# cat Gemfile //内容をコピー
# cd /home/redmine/redmine
# vi Gemfile` //さきほどコピーした内容を追記
```

RedmineのGemfileでBundlerを実行します。

```
# bundle install`
```

### ドッカ―から抜け出して再起動

```
# exit
$ docker-compose restart
```

### Redmineにアクセス
http://localhost:10083
をブラウザで開き、管理ユーザでログインします。

初期設定のユーザID/PWはこちらに載っています。
https://github.com/sameersbn/docker-redmine#quick-start

その後、管理 > プラグイン
にSlackプラグインが追加されていれば成功です。

![スクリーンショット 2018-11-01 20.15.51.png](https://qiita-image-store.s3.amazonaws.com/0/140953/f62e594f-8155-74a6-4bac-84b29ebee4a7.png)


# 手順で失敗した時につかったコマンドなど
### Dockerコンテナの表示/削除

```
$ docker ps -a
$ docker-compose down -v
```

### Dockerイメージの表示/削除

```
$ docker images
$ docker rmi [DockerID] 
```

### Docker内のログを見る

```
$ docker exec -it redmine_redmine_1 bash
# cd /home/redmine/redmine/log
```

### postogresqlのコンテナ内でデータベースにアクセスする

```
$ docker exec -it redmine_postgresql_1 bash
# psql -U redmine -d redmine_production
```

# 参考記事
**Bitname-Redmine docker コンテイナーでプラグ・インを設置する過程**
https://qiita.com/cheuora/items/e9f3bce63dcbd7f42496
**さくっとredmine+slack連携してチーム作業を始めたい**
https://qiita.com/iaoiui/items/3b642a95225a92793634

# 関連記事
**Docker立ち上げたらネットがつながらなくなった話**
https://qiita.com/mgmgOmO/items/7deb8cad52458a63d36f
**もぐみのTwitter**
https://twitter.com/mgmgmogumi

何か不明な点や間違っている点があればご指摘ください。
Rubyで組み合わせの取り出しを行う関数＜combination＞を作ってみた．permutationの結果で逆から見て同じものはいらない場合の話．

# きっかけ
かの有名な`TravelingSalesman問題`を勉強中に，各点を巡回した場合の距離の最小値を探そうとしたのですが．各点へ行く順番の組み合わせを求める必要があったのでそのお話．

例）
とあるセールスマンが[1, 2, 3, 4]の御宅を回って本社に戻る．どの順番で行けば一番距離が短くて済む？
って問題なので`0 = 本社`とした場合に[0, 1, 2, 3, 4, 0]や[0, 3, 2, 1, 4, 0]等々の全通りでどれが一番距離が短いかを調べたい！

RubyのArrayクラスには標準でpermutationメソッドという順序を考慮した組み合わせを返してくれるメソッドがありまして，それを使うと以下の様になりますね．

```ruby
nums = [1, 2, 3]
nums.permutation(3) do |item|
  p item
end

__END__
以下出力結果
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
```

この出力って順序逆にしたら同じだよねということに気づきました！
配列の順序を逆転して同じ順序の配列は不要なので，そう行った配列を返さないメソッドを自分で作ろうかなと思います:kissing:

しかし！！！:frowning2:
もしかしたら標準ライブラリ等のどこかにそんなメソッドははすでに存在しているのかもしれませんね．

でもまぁ僕は作ってみます:angel_tone2:

# メソッド

とりあえずコードをぺたり

```ruby
def combination(hashes: [{id: Int, x_point: Float, y_point: Float}], from_index: Int, to_index: Int)
  exchanges = [] # 各組み合わせ結果を追加していく配列
  count = 0 # forの繰り返しの回数
  first_array_nums = [] # count_in_same_first_array_num毎に配列先頭の要素を追加していく
  count_in_same_first_array_num = 1 # 配列先頭の要素が同じ組み合わせの個数
  for i in 0...(to_index - from_index)
    count_in_same_first_array_num *= (to_index - 1 - from_index - i + 1)
  end
  hashes[from_index..to_index].permutation(to_index - from_index + 1) do |item|
    first_array_nums << item[0][:id] if count % count_in_same_first_array_num == 0
    exchanges << item if !first_array_nums.include?(item.last[:id])
    count += 1
  end
  exchanges
end
```

今回はあくまで，`TravelingSalesman問題`を扱うので各点のデータを`[{id: Int, x_point: Float, y_point: Float}]`の形式で格納している程で使えるメソッドです．

# 解説
僕はこの様にまず考えました．

```ruby
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

#上から見た配列の要素0番目が，それ以降の配列の最後尾にきている配列は重複している！ 
```

そこで各配列の先頭の値を`first_array_nums`にappendしていきます．

しかし同じ数字ばかりappendしても使い勝手が悪い変数になるので，配列先頭の要素が同じ組み合わせの個数を`count_in_same_first_array_num`に代入するのでこれを目安に`first_array_nums`に値をapendしていきます．

`count_in_same_first_array_num `の値は`(先頭以外の要素の数)!`の値なので以下の様に決定する．

```ruby
for i in 0...(to_index - from_index)
  count_in_same_first_array_num *= (to_index - 1 - from_index - i + 1)
end
```

そして'first_array_nums'含まれる数字が要素0番目にくる組み合わせは返り値には加えない様にしています！

これでおしまい．:zipper_mouth:

# 補足
引数の`from_index: Int, to_index: Int`は`hashes`の要素の何番目から何番目まででこのメソッドで出力するかを決めています．(よく考えたら，それは引数に値を代入する場合に`[1..5]`みたいな感じですればいいかも)
CircleCIでModuleNotFoundError

CircleCI上でtoxコマンドを走らせたときに、テストファイルから自作の外部ファイルを読み込めず消耗したのでメモを残す。

## 概要


```
.
├── test_apis.py
├── tox.ini
└── utils.py
```

`test_apis.py`がテストが書かれたファイルで

```test_apis.py
# coding: utf-8

from utils import HOGEAPI 
from unittest import TestCase
```

と書いて、`utils.py`から自作クラス`HOGEAPI`をimportして、CircleCI上で`tox`すると


```
==================================== ERRORS ====================================
________________________ ERROR collecting test_apis.py _________________________
ImportError while importing test module '/home/circleci/myapp/test_apis.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_apis.py:4: in <module>
    from utils import HOGEAPI
E   ModuleNotFoundError: No module named 'utils'
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.09 seconds ============================
ERROR: InvocationError for command '/home/circleci/myapp/.tox/py36/bin/py.test' (exited with code 2)
```

と` ModuleNotFoundError`が出て自作クラスを読み込めない。ちなみにローカルで`tox`した場合は上手くいく。


# 原因

[CircleCiにssh](https://qiita.com/hinatades/items/ca7a2f353bd02a8a0956)してパスを確認してみると、

```
(env) circleci@2dca847161e3:~/myapp$ python
Python 3.6.1 (default, Jul  8 2017, 05:00:20) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload']
>>> 
```

CircleCIのPythonがインポートできるパスに、ローカルが追加されていなかった。

よって、こう書いてパスを追加したら上手く言った


```test_apis.py
# coding: utf-8

import os
import sys
from unittest import TestCase

sys.path.append(os.getcwd())

from utils import HOGEAPI  # noqa: E501
```


※ importを上部にまとめていないとflake8に引っかかるので、`# noqa: E501`を追記


### 参考

- [CircleCI2.0にSSH](https://qiita.com/hinatades/items/ca7a2f353bd02a8a0956)
すごいH本読んだからまとめ 1 「関数の呼び方、関数の定義の仕方」

## はじめに

* [すごいHaskellたのしく学ぼう](https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86%EF%BC%81-%EF%BC%AD%EF%BD%89%EF%BD%92%EF%BD%81%EF%BD%8E%EF%BC%AC%EF%BD%89%EF%BD%90%EF%BD%8F%EF%BD%96%EF%BD%81%EF%BD%83%EF%BD%81-ebook/dp/B009RO80XY)を読んだのでちょっとずつまとめていきたい。まとめていきたい。



### ghciを使ってみる

* この本ではghciを使ってコードの説明をしている。
* ghciはHaskellのインタラクティブ実行環境
  * pythonのjupyter notebookとか、javascriptのコンソールのようなもの。
* 今どきのHaskellerはstackとかいうものを使っているらしいのでghciを使うために[stackをインストールする](https://qiita.com/Akira_Kido_N/items/93b9c7d332bbea07c8a2)と良いらしい。
* stackからghciを起動するコマンドは`stack ghci`

### 計算をやってみる

#### 数の計算

```Haskell
ghci> 6 + 2 * 3 -- ちゃんと掛け算から計算してくれるかチェック
12 -- 計算には優先順位がある

ghci>(6 + 2) * 3 --()をつけたときの実行順をチェック
24 -- ()でくくられると優先的に計算される。
```

#### 論理演算子

```Haskell
ghci> True && False -- AND
False  
ghci> True && True -- AND
True  
ghci> False || True -- OR  
True   
ghci> not False  -- OR
True  
ghci> not (True && True)  -- NOT 
False -- NOT (True) 
```

#### 等しいかどうか

``` Haskell
ghci> 5 == 5  
True  
ghci> 1 == 0  
False  
ghci> 5 /= 5  
False  
ghci> 5 /= 4  
True  
ghci> "hello" == "hello"  
True 

ghci> 1 == '1' -- 別の型を比較
<interactive>:5:1: error: -- エラー出る。素敵
    ? No instance for (Num Char) arising from the literal ‘1’
    ? In the first argument of ‘(==)’, namely ‘1’
      In the expression: 1 == '1'
      In an equation for ‘it’: it = 1 == '1'

```

* ある型の値が`何`を持って`等しい`とするかの定義を`型クラス`で行う事ができる。

### 関数呼び出し

#### 関数の呼び方

* succは引数の「次の値」を返す関数
* ある型の値が`何`を持って`次の値`とするかの定義を`型クラス`で行う事ができる。

``` Haskell
ghci> succ 8 -- スペース区切りで引数を渡せる。  
9 -- 9は8の次の数
ghci> min 9 10 -- 複数渡すこともできる。  
9   
```


#### 関数の優先順位
``` Haskell
ghci> succ 9 + max 5 4 + 1 -- まずsuccとmax関数が実行される
16  
ghci> (succ 9) + (max 5 4) + 1  
16
ghci> succ 9 * 8 -- 9*8(=72)の次の値を計算しようとする
80 -- 先にsuccが効いちゃって、10*8の値が返ってきちゃう(10はsucc 9)
ghci> succ (9 * 8) -- ()でくくると上手く計算できる
73
```

* 四則演算子とかは他の関数より実行順位が遅めに設定されている模様

#### 引数が2つのときの便利記法
``` Haskell
ghci> div 10 2
5
ghci> 10 `div` 2 -- バッククォートで中起き演算子になる。(直感的にわかりやすい)
5
```


#### 計算順関連でなんかつまったところ
``` Haskell
ghci> succ succ 8 -- 10の出力を期待

<interactive>:13:1: error: -- 左から実行するのでまずsuccにsuccをやっちゃう
    ? Non type-variable argument in the constraint: Enum (a -> a)
      (Use FlexibleContexts to permit this)
    ? When checking the inferred type
        it :: forall a. (Enum a, Enum (a -> a), Num a) => a

ghci> succ (succ 8) -- 計算の優先順を変更
10 -- 成功  
```

### 関数を定義する


ghci起動した場所と同じディレクトリに.hs拡張子のファイルを置いて書く

```Haskell
-- 足し算
myPlus x y = x + y

-- 差の絶対値
myNumericalDifference x y = if x > y -- Haskellもif文使える
    then x - y
    else y - x -- Haskellではelse節が必須（Haskellの関数はなにか返さないといけない）
```

関数をロードして実行。

```Haskell
ghci> :l <定義したファイルの名前> -- ファイルロード
[1 of 1] Compiling Main             ( myfunction.hs, interpreted )
Ok, one module loaded.]
ghci> myPlus 3 2 --関数実行
5
ghci> myNumericalDifference 5 6 -- 関数実行
1
ghci> myNumericalDifference 6 5
1
```
全くのゼロから始めるボードゲームのプログラミングと機械学習 [3日目]

#前回の振り返り
[全くのゼロから始めるボードゲームのプログラミングと機械学習 \[2日目\] \- Qiita](https://qiita.com/Coshian23/items/4d6bd283c669d9da905a)

- Pythonでゲームを作るにあたって参考とする書籍の紹介
- Pythonを使い始めました
- Pythonはひとまず書籍に合わせて2系で

なんとかかんとかPythonを使い始めました。しかしながらゲーム制作への道のりはまだまだ長そうです。

#クラスの定義
前回で変数やループなどプログラムの初歩は学んだので、いよいよ核となるクラスに進んでみたいと思います。とはいえ、この辺も根本的なところはJavaと似通っているのでそれほど真新しい発見は無いかなと言う感じです。

```Python:tank.py
class Tank(object):
    def __init__(self, name):
        self.name = name
        self.alive = True
        self.ammo = 5
        self.armor = 60

    def __str__(self):
        (省略)

    def fire_at(self, enemy):
        (省略)

    def hit(self):
        (省略)

    def explode(self):
        (省略)
```
サンプルで作成した戦車のクラス。
\_\_init\_\_はコンストラクタでありクラス生成の際の初期情報を設定、\_\_str\_\_はprintなどで表示する際の情報となるようです。それぞれに「self」の引数が入っていることに注意。本書に関わらずどのサイトでもselfはお約束として入れてくださいと記載があります。とりあえず入れておけばいいのだなと理解はしましたが、詳しいところはまだ勉強できていません。

ゲームらしく戦車のクラスということで弾倉やアーマーと言った情報を持ってます。そしてfire_atという誰かに弾を撃つ関数や、弾がヒットした時のhit関数、そしてアーマーがなくなった際のexplodeつまり爆発の関数があります。

オブジェクトに対して状況や説明、そして行動といった情報がまとめて含まれていることはオブジェクト指向としては実に当たり前のことなんですが、こうやってゲームに当てはめて考えてみると実に効率的なものに感じますね。

#標準ライブラリの使用
Pythonの魅力は何と言ってもその豊富なライブラリではないかと自分は思います。標準でもかなりのモジュールやパッケージが用意されている（らしい）し、Pygameをはじめゲームに役立つパッケージや機械学習に必要なパッケージも数多く存在しています。とりあえずはボードゲームでよく使いそうなrandomパッケージを使ってみます。

```python
>>> import random
>>> random.randint(1,6)
1
```
ボドゲ必須といえるサイコロ乱数です。importでrandomモジュールをインポートすることでランダムな整数を生成するrandint関数が使えるようになりました。

```python
>>> from random import randint
>>> randint(1,6)
2
```
fromとimportでrandomのrandint関数だけインポートもできます。

##randomが生み出す乱数は本当の乱数ではない
randomが生み出す乱数は「疑似乱数」であり本当の乱数ではないという記載がありました。確かにコンピュータは真の乱数は生み出せないし、あくまで複雑な関数を経てランダムに見える数字を生み出しているだけと言えますね。ゲーム攻略動画とかを見てると「乱数調整」などといった言葉も耳にしますし、特定のパターンを任意に発生させたりしてますね。

randomにはseed関数があり、同じseedを設定してあげると毎回同じパターンの乱数を生み出します。

```python
>>> random.seed(100)
>>> random.randint(1,100)
15
>>> random.randint(1,100)
46
>>> random.randint(1,100)
78
>>> random.seed(100)
>>> random.randint(1,100)
15
>>> random.randint(1,100)
46
>>> random.randint(1,100)
78
```

#今後の予定
1. ボードゲームをプログラミング
    2. Pythonの基礎勉強
    3. Pygameの基礎勉強　👈
2. ボードゲームのAI作成
3. 機械学習によるAI強化

一通りPythonの基礎を学びましたので、次はいよいよPygameの章に入りたいと思います。

#今回の振り返り
- やったこと
    - Pythonでクラスを定義
    - モジュールをインポート
- わかったこと
    - \_\_init\_\_や\_\_str\_\_の役目
    - fromとimportの使い方
    - randomは擬似乱数
- つぎにやること
    - Pygameのインストール
    - Pygameを使ってみる
【Ruby】コーディングメモ（Hello World、計算式、変数値メッセージ出力、ランダム値、偶数・奇数の判定、サンプルプログラム）

#Hello Worldのメッセージ出力

- 文字列を出力する際は、putsメソッドを使用します。
- js、PHP、Java等と異なり、末尾のセミコロンは不要です。

```hello.rb
puts "Hello World"
```

**出力結果**

```
Hello World 
```

- ちなみに、putsメソッドは改行込みで出力します。よって、putsを2回繰り返し呼び出した際は、出力結果に改行されて出力されます。以下のとおり

```hello.rb
puts "Hello"
puts "World"
```

**出力結果**

```
Hello
World 
```

- 改行無しで出力したい場合はprintメソッドを使用します。

```hello.rb
print "Hello"
print "World"
```

**出力結果**

```
HelloWorld
```

#計算式

- 他の言語と変わり有りません。
- 足し算：+、引き算：-、掛け算：*、割り算：/、剰余：%

``` calc.rb
a = 3
b = 2
puts a + b
puts a - b
puts a * b
puts a / b
puts a % b
```

**出力結果**

```
5
1
6
1
1
```

#変数値をメッセージフォーマットとして出力

- 「#{変数}」の表現で、変数値を文字列として出力することが出来ます。

``` hensu.rb
name = "田中 一郎"
job = "システムエンジニア"

puts "#{name}さんは#{job}です"

# 以下の書き方でも同じですが、上記のほうがスマートですよね。
# puts name + "さんは" + job + "です"
``` 

**出力結果**

```
田中 一郎さんはシステムエンジニアです
```

#ランダム値の生成

- randメソッドを使用します。
- rand(100)と引数に100を渡すと、0~99までのランダムな整数値を返します。
- rand(1..99)と範囲を指定することも可能です。この場合、1~99までのランダムな整数値を返します。

``` rand.rb
puts rand(100)
puts rand(1..99)
``` 

**出力結果**

```
78
4
```

#偶数、奇数の判定

- 偶数の判定は evenメソッドを使用します。偶数の場合、trueが返却されます。
- 奇数の判定は oddメソッドを使用します。奇数の場合、trueが返却されます。


``` even_or_odd.rb
# 以下、整数値1をeven、oddで偶数か奇数か判定しています。1は奇数なので、oddでtrueが帰ってくることを期待しています。
puts 1.even?
puts 1.odd?
``` 

**出力結果**

```
false
true
```

#復習

- ランダムな整数値を生成して、奇数か偶数か判定して、メッセージを出力するコードを書いてみました。

``` sample.rb
#ランダムに1から10の値を生成
number = rand(1..10)

print "#{number}は"

if number.even?
    puts "偶数です"
else
    puts "奇数です"
end

``` 

**出力結果**

```
2は偶数です
```
JavaでSingletonパターン

# はじめに
[GoF](https://ja.wikipedia.org/wiki/ギャング・オブ・フォー_(情報工学))のデザインパターンを紹介している[『増補改訂版 Java言語で学ぶデザインパターン入門』](https://www.amazon.co.jp/増補改訂版Java言語で学ぶデザインパターン入門-結城-浩/dp/4797327030/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&psc=1&refRID=2ZE4GPYNN55JGDR5QMHP)を読んで、学んだ内容についてまとめます。

# Singletonパターン
## Singletonとは
日本語に訳すとトランプの1枚札のことで、全体の集合の中で1つしか存在しないものを意味します。
このことから**システム全体でインスタンスが1つしか存在しないことを保証するパターン**のことを**Singletonパターン**と言います。

## 登場人物
Singletonパターンで使用するのは以下のクラス図に登場するクラスです。
と言ってもSingletonクラスの1つしかありません。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278934/a0104997-0b79-eed7-4363-b279631d0a13.png)

## 具体例
具体例として、singletonクラスと実行クラスをもとに説明します。

### 実装クラス
- **Singletonクラス**  
 
```java:Singleton.java
package singleton;

public class Singleton {
	// 1.staticフィールド(クラス変数)としてsingletonを定義
	private static Singleton singleton = new Singleton();

	// 2.privateなコンストラクタ
	private Singleton() {
		System.out.println("インスタンスの生成に成功しました");
	}

	// 3.singletonインスタンスの返却
	public static Singleton getInstance() {
		return singleton;
	}
}
```
ポイントは以下の3点です。
  **1.**privateなクラス変数として`singleton`が定義されている。
  **2.**コンストラクタがprivateになっており、他のクラスから呼び出すことができない。(newできない)
  **3.**singletonインスタンスを返却する`getInstance()`メソッドを定義している。

補足の説明を行います。
まず、外部のクラスからpublicな`getInstance()`メソッドが呼ばれます。
その際に初めて呼ばれる場合は、Singletonクラスの初期化が行われ、その時に一度だけSingletonクラスのインスタンスが生成されます。
以降、`getInstance()`メソッドが呼ばれる場合は既に生成したSingletonクラスのインスタンスが返されます。
コンストラクタ内ではインスタンスの生成が成功したことが分かるように出力を行っていますが、通常は不要です。

### 実行クラス
- **Mainクラス**  
`getInstance()`メソッドを2回呼び出し、同じインスタンスを取得していることを確認します。 

```java:Main.java
package singleton;

public class Main {
    public static void main(String[] args) {
        System.out.println("***実行クラス開始***");
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        if (obj1 == obj2) {
            System.out.println("obj1 is obj2");
        } else {
            System.out.println("obj1 is not obj2");
        }
        System.out.println("***実行クラス終了***");
    }
}
```
### 実行結果
`Main.java`を実行した結果は以下になります。
`obj1 is obj2`が出力されており、同一のインスタンスを取得できていることが確認できます。

```:実行結果
***実行クラス開始***
インスタンスの生成に成功しました
obj1 is obj2
***実行クラス終了***
```

## メリット
Singletonパターンを利用することで、システム全体でインスタンスが1つしか存在しないことが保証できます。
このようにすることで、複数のインスタンスが絡み合い、思いがけないバグが発生してしまうことを未然に防ぐことができます。

# まとめ
インスタンスが1つしか存在しないことを保証するSingletonパターンに関して学びました。
以下でサンプルコードをアップしていますのでよろしければ参考にどうぞ。

- [Singletonサンプルコード](https://github.com/masayuki777/study/tree/master/DesignPatterns/05_Singleton)

また、他のデザインパターンに関しては以下でまとめていますので、こちらも参考にどうぞ。

- [[随時更新]Javaでデザインパターンまとめ](https://qiita.com/mk777/items/4e13505b654fc21c76a2)

# 参考文献
- [増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/増補改訂版Java言語で学ぶデザインパターン入門-結城-浩/dp/4797327030/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&psc=1&refRID=2ZE4GPYNN55JGDR5QMHP)
【書評】マンガでやさしくわかるアサーション

*アサーション* というコミュニケーション手法に関する本の感想です。

マンガが多く差し込まれていてとても読みやすく、１〜２時間もあれば読める分量でした。入門本としておすすめな印象です。

最近流行りの「ティール組織」で新しい組織の形に移行していこうとする中で３つのブレークスルーがあると言われていますが

- セルフマネジメント
- ホールネス

この２つのブレークスルーにおいては

*自分が思っていることが素直に出せる状態*

が大事な要素になると思います。※心理的安全性の確保
それは、仕組みだけでどうなるというわけではなく
関わる一人一人が自分に素直にコミュニケーションしていくことが求められるわけでして、そこでこの *アサーション* について学ぼうと思い読みました。


似たような手法に NVC（非暴力コミュニケーション）があります。
正直違いがよくわからないくらい似たような考え方なのですが、どちらもおすすめです。
NVCの本はちょっとぶ厚めなので、入門としてはこちらの本が良いかもしれません。


以下、キーワードメモ。

## アサーションとは
自分も相手も大切にする自己表現

## 自己表現の種類
- 攻撃的自己表現
    - 頼むのではなく命令
        - 自信が無いことの現れ
- 非主張的自己表現
    - 何も言わない。Noと言えない。
        - 思い込みに縛られている状態

## 心構え
- オープン
	- 自分に素直に
- 傾聴
	- 相手への好奇心、聴く
- 追加で一言
	- オープン・クエスチョン
	- 追加で一言加えることで、会話に幅をもたせる
- 言行一致
	- 非言語的な部分（身振り、手振り、表情など）も相手に伝わる

## DESC法
### D
- 客観的な事実を描写して
    - 「予定より１０分会議が伸びています」

### E
- 自分の気持ちを表現したり、相手の気持ちに共感し
	- 「皆さんもそう見えますが、私も疲れてきました。次の会議も控えているので、そろそろ出たいです。」

### S
- 妥協案・解決策など特定の提案をし
	- 「続きは次回にしませんか」

### C
- 断られた時の選択肢も示す
	- 「お先に失礼します。」
Vultrに立てたCentOSサーバにnginxを導入する

試しにVultrのVPSを使ってみているので、その導入メモ。
インスタンスは、デフォルトのCentOS 7を選択して作成した。

# nginxのインストール

`nginx.repo`ファイルを作成してyumのリポジトリを追加する。

```
$ sudo vi /etc/yum.repos.d/nginx.repo
```

```:nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1
```

yumを使ってnginxをインストール。
```
$ sudo yum install nginx
```

起動時にnginxが自動で立ち上がるように設定。
```
$ sudo systemctl enable nginx
```

nginxの起動。
```
$ sudo systemctl start nginx
```

# CentOSのファイアウォールの設定

CentOS 7系のファイアウォールはデフォルトでfirewalldになっているので、ここにhttp(80番)とhttps(443番)を許可するように設定を追加する。

まずファイアウォールが有効であることを確認。

```
$ sudo systemctl status firewalld
...
Active: active (exited)
...
```

が返ってくればOK。起動していない場合は下記のコマンドで起動する。
`$ sudo systemctl start firewalld`

publicゾーンに設定されているサービスを調べる。

```
$ sudo firewall-cmd --list-services --zone=public --permanent`
dhcpv6-client ssh
```

初期状態だとdhcpv6-clientとsshが含まれている。
ここにhttpとhttpsを追加する。

```
$ sudo firewall-cmd --add-service=http --zone=public --permanent`
$ sudo firewall-cmd --add-service=https --zone=public --permanent`
```

結果を確認。

```
$ sudo firewall-cmd --list-services --zone=public --permanent
dhcpv6-client ssh http https
```

80番や443番以外のポートを使う場合は、`/usr/lib/firewalld/services/` にある`http.xml`や`https.xml`を`/etc/firewalld/services/`にコピーし、中身のポート番号を変更すればよい。

設定できたらfirewalldをリロードする。
```
$ sudo systemctl reload firewalld'
```

# Vultrのファイアウォールの設定

続いてVultr側のファイアウォールを設定する。ファイアウォールの設定は、Webコンソールの[Servers]-[Firewall]の画面で行う。まだグループを作っていない場合は、[Add Firewall Group]で任意の名前のグループを作成できる。

![181103-0005.png](https://qiita-image-store.s3.amazonaws.com/0/46062/d57b9aeb-136b-a8c7-7947-0f03eb32744f.png)

Web用に80番と445番、SSH用に22番、それとping用にICMPプロトコルを許可した例は次のような感じ。その他のポートへのアクセスは全て拒否する。IPv6を使っている場合は、左のタブからIPv6 Rulesを選んで同様に設定する。

![181103-0007.png](https://qiita-image-store.s3.amazonaws.com/0/46062/6a206aac-a4fd-c2ea-e33c-5ff83d4dfdfa.png)

サーバにこのファイアウォールグループを適用する。[Servers]からサーバを選んで、上部メニューで[Settings]を選ぶと、次のように左に一覧が出てくるので、[Firewall]を選ぶと次の画面になる。ここで作成したファイアウォールグループを選んで[Update Firewall Group]を押せば適用される。

![181103-0004.png](https://qiita-image-store.s3.amazonaws.com/0/46062/21ffd1f4-bac4-fce5-1936-6f9f4444517e.png)

# ブラウザで確認

Webブラウザから `http://サーバのIPアドレス` にアクセスして、デフォルトページが表示されれば完了。

![181103-0008.png](https://qiita-image-store.s3.amazonaws.com/0/46062/8ff1321d-48c8-f526-7610-faff19367404.png)
ループ文

##まえおき
プログラミング初心者が独学で学習中。
手探り状態であるためいろいろとツッコミどころは満載かもしれません。

##目的
学習を進めていく中で、学習言語を広げていくと、過去にやった内容であっても文法とかがこんがらがってたりして、再度検索する、なんてことが多いなと思ったので、初歩的なことであっても自分用メモとして残すことにしました。

###ループ文

####Java
#####for文

for(変数の用意; 繰り返し条件; 変数の更新)

```java:qiita.java
for(int i = 0; i < 5; i++) {
  System.out.println(i); // 処理
}
=>
1
2
3
4
5
```

#####拡張for文

for(型 変数の用意 : 処理したい配列)

```java:qiita.java
String[] team = {"勇者", "戦士"} 

for(String member : team) {
  System.out.println(member); // 処理
}
=>
勇者
戦士
```

####Ruby
#####for文

for 変数 in 繰り返しの回数

```ruby:qiita.rb
for i in 1..5
  puts i
end
=>
1
2
3
4
5
```

#####times文

回数.times do

```ruby:qiita.rb
5.times do 
  puts "繰り返します"
end
=>
繰り返します
繰り返します
繰り返します
繰り返します
繰り返します
```
【Ruby】コーディングメモ（文字列操作など）

##文字列を大文字に変換

```sample.rb
puts "Hello World".upcase

(出力結果）
HELLO WORLD
```

##文字列を小文字に変換

```sample.rb
puts "Hello World".downcase

(出力結果）
hello world
```

##エンコードの取得、文字列長の取得、バイト数の取得

```sample.rb

hello = "こんにちは。世界"
puts hello.encoding
(出力結果）
UTF-8

puts hello.length
(出力結果）
11

puts hello.encoding
puts hello.bytesize
(出力結果）
8
```
GCPで１clickデプロイしたwordpressをSSL化する方法

この記事が一番参考になった。

https://www.onepagezen.com/free-ssl-certificate-wordpress-google-cloud-click-to-deploy/

ほぼ和訳しただけだが、自分用のメモとして残しておく。


## 1. SSHでサーバーに接続する

GCPはこれが楽。個

## 2. CertBot Clientをインストールする
```
$ wget https://dl.eff.org/certbot-auto && chmod a+x certbot-auto
```

## 3. 証明書を作成する

`1pagezen.com`部分は各々で取得したドメインで設定

```
$ ./certbot-auto certonly --webroot -w /var/www/html/ -d 1pagezen.com -d www.1pagezen.com
```

`/etc/letsencrypt/live/1pagezen.com/fullchain.pem`

上記のディレクトリに秘密鍵がインストールされる。

※ wwwを設定しない場合は、入れると上手くインストールされなかった。 末尾の`-d 1pagezen.com`は削除してもいいかも。

## 4. 証明書を設定する


```
$ sudo vi /etc/apache2/sites-available/default-ssl.conf
```

下記の記述を`default-ssl.conf`の一番上にペースト。

```default.conf
<Directory /var/www/html/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
```

次に、証明書の所在を明示する。デフォルトで設定されている記述が同ファイルにあるため、コメントアウト。
生成した証明書の所在を下記のように追加。

```
SSLCertificateFile "/etc/letsencrypt/live/1pagezen.com/cert.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/1pagezen.com/privkey.pem"
SSLCertificateChainFile "/etc/letsencrypt/live/1pagezen.com/chain.pem"
```

## 5. httpsリダイレクトを設定する

```
$ sudo vi /etc/apache2/sites-available/wordpress.conf
```

既存で<Directory>の記述が3行あるが、それは削除。
代わりに下記を追加。例に倣って、`1pagezen.com`は各々が取得したドメインで設定。

```
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

ServerName www.1pagezen.com
ServerAlias 1pagezen.com
Redirect permanent / https://www.1pagezen.com/

<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/html/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

## 6. Apatcheを再起動する
```
sudo a2ensite default-ssl
```
```
sudo a2enmod ssl
```
```
sudo service apache2 restart
```
自分の場合は、最後のコマンドは`service`ではなく`systemctl`をコマンドを使用。

```
sudo systemctl restart apache2
```

restartの前に、`reload`しろとか言われるが、それはよしなにやる。


## 7. WordpressのURLをアップデートする

wordpressの設定画面に入って、`http://`部分を`https://`に変更して設定はおしまい。
【Java】ジェネリクスのサンプル

#ジェネリクスとは

- データ型を固定しないで、クラス、メソッド定義を行える技法
- ジェネリクスのメソッドはオーバーロードでも代替出来る。が、オーバーロードは複数メソッドを定義しなくてはならないが、ジェネリクスを使用すると、1つだけメソッドを定義するだけですむのでスマートである。

#サンプル

```Sample.java
// ジェネリクスを使用したクラス
class Hello<T> {
	T data1;
	
	// コンストラクタ
	public Hello(T data) {
		this.data1 = data;
	}
	// メソッド
	public T getData1() {
		return data1;
	}
}
// 呼ぶ側のクラス
public class Sample {
	public static void main(String[] args) {
		// String型
		Hello<String> s1 = new Hello<>("String");
		System.out.println(s1.getData1());

		// Integer型
		Hello<Integer> s2 = new Hello<>(100);
		System.out.println(s2.getData1());
		
	}
}
```

## 呼んでみる

```sh
javac Sample.java
java Sample
```

##実行結果

```
String
100
```
【Java】ラムダ式

#ラムダ式について

- メソッドを変数のように扱える式です。

**構文**
**` (変数) = (メソッドの引数) -> {処理内容}`**

- 匿名クラスの記載を関数型で記載可能となります。
- [【Java】匿名クラスについて](https://qiita.com/yut-nagase/items/60ebba2aef19f26f5430)　で説明した匿名クラスを更にシンプルに、1行で記載できる形となっています。
- サンプルを見ながら、ご確認下さい。


```Sample.java
// 匿名クラス、ラムダ式で使われるインターフェース
interface I_Hello {
  public void print();
}

// 呼ぶ側のクラス
public class Sample {
	public static void main(String[] args) {
		// 匿名クラスの書き方
		I_Hello p = new I_Hello() {
			@Override
			public void print() {
				System.out.println("Hello World");
			}
		};
		p.print();

		// ラムダ式の書き方
		I_Hello p2 = () -> { System.out.println("Hello World2"); };
		p2.print();

	}
}
```

- 実行結果

```
Hello World
Hello World2
```
スクレイピング対策の対策についての所感

#スクレイピング対策について

直近でECサイトをいくつかスクレイピングする業務に携わっていました。
ただ、スクレイピング用のスクリプトを回していてしばらくすると
以下のようなポップアップが出ることがあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/160512/41f8c00a-53c5-ca54-01e7-958803b8dde1.png)

例えばこのAmazonの例だと、このポップアップが出るとこいつが邪魔をして処理が進まなくなってしまいます。

サイト側も情報を取られたくないので、こういった外部からの機械的なアクセスを遮断するための対策を講じています。
「いやWebサイト上で誰でも見れる情報だから守る意味がないのでは？」と思った方もいるかもしれませんが、ECサイトではレビュー情報や販売データを企業に販売しているケースがあり、そのデータが勝手に抜かれていると困るのです。
![守る.jpg](https://qiita-image-store.s3.amazonaws.com/0/160512/ff89e796-d5f8-69e7-abd4-f6045e8e6622.jpeg)

私の場合ECサイトの動向を追うため定期的に同じサイトをスクレイピングしていたため、よくこの類のポップアップに邪魔されていました。
そうなってくると「スクレイピング対策の対策」が必要になってくるわけです...

##対策その①　プロキシ外から通信させる：効果△
業務としてスクレイピングやクローリングをされる場合、社内のプロキシを通して行う場合が多いと思います。
私は「プロキシを通すってことは、外から見えるIPアドレスがずっと同じになるから止められやすいのでは！？」と考えました。

私の部署ではプロキシを通さずに直接外に出す無線LANが存在するため、そちらを使ってスクレイピングを実行してみました。

結果的には**「調子がいい時もあれば悪い時もある」**という具合です。笑
正直、プロキシ云々はあまり関係ないような気がします...
社内から実行してあまりに弾かれるときなどに、無線を使ってチャレンジしてみるとたまに通る時があったりしたのでネットワークをちょこちょこ変えるのは意味があるのかもしれません。知らんけど。

##対策その②　処理する速度を落とす：効果○
私の場合、スクレイピングの処理の中で何度もページをめくる処理が入っていました。
最初は何の設定もしていなかったのですが、ページの情報を取得してから次のページに遷移する前に処理を指定時間止めるようにしました。
Pythonであれば`sleep`で簡単に指定できます。

スクレイピング処理を人間の動きに近づける、という考えですね。

2,3秒では効果は薄く、10~15秒程止めるとかなり効果がありました。
※ネット上では「5秒」で効果があるという記載が多かったですが私の現場では10秒で目に見えて効果が出ました。

ただし、当たり前ですが毎ページ○○秒止めるというのは**実行時間が爆発的に増えます。**
そこらへんは状況にあわせてチューニングする必要があります。

##対策その③　処理する量を減らす：効果○
先程のその②に似ていますが、一度に処理する量を減らすということです。
例えば100ページのスクレイピングをしなければならないとすると
月～金に20ページずつ処理して1週間で100ページ終わらせるという具合です。

私の業務はウィークリーで情報を取得する必要があっため
上記のように処理をできるだけ分散させることで、現象の発生を軽減できました。

##対策その④　ユーザーエージェントを設定する：△
ある日先輩に「てか、ユーザーエージェントって設定してる？」と言われました。
「何言ってるんだこの人は」と思いながら話を聞いてみると
「まずそこから対応しなきゃじゃん...」ってなもんでした。

ユーザーエージェントについてはこちらのページを読んで見てください。

https://qiita.com/arribux/items/4c2b3382ca71f29a6b8a
「Ruby Mechanize でスクレイピングをするときに User-Agent は必須」

とりあえずユーザーエージェントを設定しないと「ロボットが動かしているということが丸わかり、ということです。

「これ設定すれば全部解決なんじゃね？」というぐらいな情報でしたが
なぜかあまり効果はでませんでした...（私の設定がちゃんとできていなかったのかも...）

私はPythonのseleniumを使っていたため以下のページを参考にしていました。
https://zafiel.wingall.com/archives/7016

詳しい方いたら、ユーザーエージェントの効果について教えてください....

#まとめ
私の業務内の経験だけで言えば、「できるだけ遅く、少ない量」にすることで
ロボットチェックを回避するという果てしなく泥臭いやり方に落ち着いてしまいました...

ユーザーエージェントの設定の他にも有効な手段があれば是非教えてください！！
[Android] KotlinとButterknifeのAnnotation Crash問題。

# 問題
```groovy
apply plugin: 'kotlin-kapt'
```
これはKotlinのannotationを使えることができる。
でも、
Butterknifeの@BindView と @RealmClassのAnnotationの
Crash問題があった。

#解決方法
Build.gradleを変えます。

#Step one

順番大事です。

```groovy
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
```

#Step Two

基本　annotationProcessor　-→　kaptに変えます。

```groovy
implementation 'com.jakewharton:butterknife:8.8.1'
kapt 'com.jakewharton:butterknife-compiler:8.8.1'
```

#Step Three
すぐ下に。

```groovy
kapt {
    generateStubs = true
}
```
【Java】匿名クラスについて

#匿名クラスとは
- ~~内部クラスとも、~~　無名クラスともいう。無名のとおり、名前の無いクラスです。
- 通常のクラスと異なり、コンストラクタと処理部分の記載を同時に行う。

#匿名クラスの実装サンプル

```Sample1.java
// 匿名クラスで使われるインターフェース
interface I_Hello {
  public void print();
}

// 呼ぶ側のクラス
public class Sample {
	public static void main(String[] args) {

		I_Hello p = new I_Hello() {
			@Override
			public void print() {
				System.out.println("Hello World");
			}
		};
		p.print();
	}
}
```

- 匿名クラスの実行結果

```
Hello World
```

#匿名クラスを使わないで実装した場合のサンプル

```Sample2.java

// インターフェース
interface I_Hello {
	public void print();
}

class Hello implements I_Hello {
	@Override public void print(){
		System.out.println("Hello World");
	}
}

// 呼ぶ側のクラス
public class Sample2 {
	public static void main(String[] args) {

		I_Hello p = new Hello();
		p.print();
	}
}
```

- 実行結果

```
Hello World
```

#匿名クラスを使う場合と使わない場合を比較して
- 上記、サンプルを見るように、匿名クラスを使わない場合、インターフェースを実体化するクラスHelloを用意しなくてはならないので、匿名クラスと比べて大掛かりとなってしまっています。
- 匿名クラスの場合はシンプルに記載できます。
コメントの残し方

##まえおき
プログラミング初心者が独学で学習中。
手探り状態であるためいろいろとツッコミどころは満載かもしれません。

##目的
学習を進めていく中で、学習言語を広げていくと、過去にやった内容であっても文法とかがこんがらがってたりして、再度検索する、なんてことが多いなと思ったので、初歩的なことであっても自分用メモとして残すことにしました。

###コメントの残し方
#####Java
行頭に　// 
複数行のコメント　/* ~ */

```java:qiita.java
// これはコメントです

/* ここから
   ここまでコメントです　*/
```

#####Ruby
行頭に　#
複数行のコメント　=begin ~ =end

```ruby:qiita.rb
# これはコメントです

=begin
ここから
ここまでコメントです
=end
【Unity】モデルにパーティカルシステムを適用する

環境メモ
⭐️Mac OS Mojave バージョン10.14
⭐️Xcode version 10.0(10A255)
⭐️Unity 2018.2.14f1
⭐️iPhone7 IOS11.4.1


Asset Store から
モデルは、「Unity Mask Man」を使用して
パーティカルは、「Particle Ribbon」を使用した。

「UnityMask」←こちらが、裸のマスクマン
実際に動かした動画はこちら↓↓
https://twitter.com/nonnonkapibara/status/1058638121883947008
<img width="375" alt="IMG_0071.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/a480872e-1185-a056-8cfd-b029353e8567.png">


「UnityMan」←こちらが、裸じゃないマスクマン
実際に動かした動画はこちら↓↓
https://twitter.com/nonnonkapibara/status/1058638796604956672
<img width="375" alt="IMG_0067.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/be606483-5ef2-6a40-3cd9-21a6b0cd777d.png">


<img width="1361" alt="001.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/6f59bd67-a7aa-b6cf-0b3e-0092cd61e0a5.png">


<img width="1358" alt="002.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/70ab5016-4232-8a12-4bdb-44d83ec4436c.png">
Node.jsアプリをLinux環境で常駐化させる　nohup編

Node.jsアプリを動かすときは、`node app.js` や `npm start`などのコマンドを実行します。
しかし、コマンド実行したターミナルからログアウトしてしまうと、アプリも終了してしまいます。
AWSでEC2立ち上げて、sshでつないで、`npm start`して、アプリが動いた！のでsshを切る、とアプリも終了してしまいます。

sshを切ってもアプリを起動しておくには、いくつか方法があります。
その中でも今日は`nohup`コマンドを使う方法です。

##コマンド
常駐化するには以下のようにコマンドを実行してアプリを起動します。

```shell
$ nohup node app.js &
```

`nohup command [コマンドの引数]`

`&`によってコマンドがバックグラウンドで実行されます。
nohupをつけることで、ログアウトしてもアプリが実行され続けます。
nohupで実行されたコマンドの、標準出力と標準エラー出力は`nohup.out`に出力されます。nohup.outはプログラムを実行しているディレクトリに作られます。(書き込み権限がない場合は、$HOMEに作られます。)

###出力先を変更する
標準出力と標準エラー出力の出力先を変更する場合は、`nohup`コマンドを実行する際に以下のようにします。

```shell
$ nohup node app.js > out.log 2> error.log &
```

`> out.log`で標準出力の出力先がout.logになり、`2> error.log`で標準エラー出力の出力先がerror.logになります。
🍶組み合わせを列挙するアルゴリズムについて(Ruby)

## 組み合わせ

Rubyで組み合わせを求める機会があった。
Rubyには便利なメソッドがあって、以下のように求めることができる。

```ruby
arr = [1, 2, 3, 4, 5]
p arr.combination(2).to_a

# OUTPUT
[[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
```

しかし、これを実際に自分で実装しようとすると意外と難しいなと感じたのでまとめてみる。

## 実装

### 考え方
直感的な考え方は、自分で樹形図を書くプロセスである。
例えば、`[1,2,3,4]`から3つの要素を取る組み合わせを考える。
まず、`1`を取る。残った`[2,3,4]`から2つを取ってきて`1`に加える。
`[1,2,3][1,2,4][1,3,4]`ができる。
次に、`2`を取る、残った`[3,4]`から2つ取ってきて`2`に加える。
`[2,3,4]`ができる。
合わせて、４つの組み合わせができる。
これは再帰的に実装をすることができる。

再帰終了条件
`[1,2,3]`から3つ取ってくるようなときは`[[1,2,3]]`を返す。
`[1,2,3]`から1つ取ってくるようなときは`[[1],[2],[3]]`を返す。

Rubyでは、インスタンスメソッド中でレシーバを省略すると`self`が暗黙的にレシーバになる。

###　コード

```ruby
class Array
  # EXAMPLE: [1.2.3.4].combination_array(3) => [[1,2,3], [1,2,4], [1,3,4], [2,3,4]]
  def combination_array(comb_size)
    return [] if comb_size > size # 4C5のようなものは空を返す
    return [] if comb_size == 0 # 4C0のようなものは空を返す
    return [self] if comb_size == size
    return map { |e| [e] } if comb_size == 1

    ret = []
    (0..size - comb_size).each do |i|
      picked = self[i]
      rest = self[i + 1..-1]
      rest.combination_array(comb_size - 1).each do |c|
        ret << [picked] + c
      end
    end
    ret
  end
end

if $PROGRAM_NAME == __FILE__
  p %i[asahi kirin sapporo suntory].combination_array(2)

  # 重複がない時(既存メソッドとの比較)
  p [1, 2, 3, 4, 5, 6, 7, 8, 9].combination_array(3) == [1, 2, 3, 4, 5, 6, 7, 8, 9].combination(3).to_a

  # 重複がある時(既存メソッドとの比較)
  p [1, 2, 3, 4, 5, 6, 1, 8, 3].combination_array(4) == [1, 2, 3, 4, 5, 6, 1, 8, 3].combination(4).to_a
end

## OUTPUT
[[:asahi, :kirin], [:asahi, :sapporo], [:asahi, :suntory], [:kirin, :sapporo], [:kirin, :suntory], [:sapporo, :suntory]]
true
true
```

#### 参考
https://blog.shibayu36.org/entry/2016/12/22/092511
【AWS】Amazon Linux2環境にMySQLをインストールしようとしてはまった

#環境
Amazon Linux2

#現象
Amazon Linux2で、MySQLをインストールしようとして、「No package mysql-server available.」のエラーメッセージが表示されてしまった。

#対応した内容

- 以下、コマンドを実行して、My SQLのパッケージが存在するか確認

```
 # yum search mysql
```

- Amazon EC2のyumリポジトリにMySQLのリポジトリが含まれていない模様。MySQL派生版のMariaDBがインストール済みですから、MySQLは含めていないんでしょうね。
- MySQLをインストールする前に、MariaDBをアンインストールしました。

```
#  sudo yum remove mariadb-libs
#  sudo rm -rf /var/lib/mysql
```

- 次に、以下のコマンドでMySQLのリポジトリを追加します。（MySQL公式サイトからyumリポジトリを追加）

```
#  rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
```

- 改めて、MySQLをインストールします。

```
# yum install mysql-community-server
```

- バージョンの確認

```
# mysqld --version
mysqld  Ver 5.7.23 for Linux on x86_64 (MySQL Community Server (GPL))
```


# 参考にさせていただいたサイト
https://enomotodev.hatenablog.com/entry/2016/09/01/225200
【RubyOnRails】AWS上に環境を構築する

#環境
Amazon Linux2

#参考にさせていただいたサイト
https://qiita.com/na0AaooQ/items/5bd62e630a2faf051a52

#必要なライブラリをインストール

```sh
yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel sqlite-devel
```

#rbenvインストール

```
git clone https://github.com/sstephenson/rbenv.git /usr/local/rbenv
cp -p /etc/profile /etc/profile.ORG
diff /etc/profile /etc/profile.ORG


echo 'export RBENV_ROOT="/usr/local/rbenv"' >> /etc/profile
echo 'export PATH="${RBENV_ROOT}/bin:${PATH}"' >> /etc/profile
echo 'eval "$(rbenv init -)"' >> /etc/profile

source /etc/profile
```

#RBENV_ROOT環境変数の有効化やrbenv init実行

```sh
env | grep RBENV
```

- 出力結果
```
RBENV_ROOT=/usr/local/rbenv
RBENV_SHELL=bash
```

#インストールしたrbenvバージョン確認

```
rbenv --version

```

- 結果

```
rbenv 1.1.1-39-g59785f6
```

#ruby-buildインストール

```
git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build
```

#Rubyインストール

```
rbenv install -l
```

- 出力結果


```
Available versions:
（略）
  2.4.4
  2.5.0-dev
  2.5.0-preview1
  2.5.0-rc1
  2.5.0
  2.5.1
  2.6.0-dev
  2.6.0-preview1
  2.6.0-preview2
  jruby-1.5.6
  jruby-1.6.3
（略）
```

- 最新に近く、かつ、安定していると思われる2.5.1をインストールすることとします。

```
rbenv install -v 2.5.1
```

- 結果

```
(中略)
installing rdoc:                    /usr/local/rbenv/versions/2.5.1/share/ri/2.5.0/system
installing capi-docs:               /usr/local/rbenv/versions/2.5.1/share/doc/ruby
Installed ruby-2.5.1 to /usr/local/rbenv/versions/2.5.1

/tmp/ruby-build.20181010161219.21156 /home/ec2-user/workdir/rbenv
/home/ec2-user/workdir/rbenv
```

- /usr/local/rbenv/versions/2.5.1 にインストールされたようなので、PATHに追加します。

```
export PATH=/usr/local/rbenv/versions/2.5.1/bin:$PATH
```

#PATHが通っているか含めて、Rubyのバージョン確認

```
ruby -v
```

- 無事にRubyコマンドも実行できるし、Pathも通っているようです。

```
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
```

#Railsインストール

```sh
gem update --system
gem install nokogiri -- --use-system-libraries
gem install --no-ri --no-rdoc rails
gem install bundler
rbenv rehash #←「~/.rbenv/versions/2.x.y/bin/ 以下に置いてあるコマンド群を ~/.rbenv/shims/以下に置いて使えるようにする」
```

#インストールしたRailsのバージョンとgem確認

```
rails -v
```

- 結果

```
Rails 5.2.1
```

```
gem list
```

- 結果

```

*** LOCAL GEMS ***

actioncable (5.2.1)
actionmailer (5.2.1)
actionpack (5.2.1)
actionview (5.2.1)
activejob (5.2.1)
(略)
zlib (default: 1.0.0)
```

- 無事に環境構築できたようです。
NuGetについて勉強したことをまとめてみた

#NuGetとは
- .NET開発におけるパッケージマネージャー
- [フリー・アンド・オープンソース（FLOSS）](https://ja.wikipedia.org/wiki/FLOSS)
- 対応する言語は、.NET FrameworkとC++ネイティブパッケージ
- パッケージで扱っているソフトウェアは、NuGetのサイトなどで確認できる

https://www.nuget.org/packages
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235774/49cca1f8-ea22-02b8-2853-5e2b1f151e0b.png)

#NuGetの操作
- NuGet パッケージ マネージャー コンソールでソフトウェアのインストールなどの操作ができる。

#NuGetのコマンド一覧(Nugetバージョン 4.6.0)

##Find-Package
- パッケージソースから利用可能なパッケージのセットを取得します。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-find-package

##Get-Package
- インストールされているパッケージのセットを取得します。 -Updatesスイッチを使用すると、パッケージソースから利用可能な一連のパッケージ更新を取得します。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-get-package

##Install-Package
- パッケージとその依存関係をプロジェクトにインストールします。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-install-package

##Uninstall-Package
- パッケージをアンインストールします。 他のパッケージがこのパッケージに依存している場合は、-Forceオプションが指定されていない限り、コマンドは失敗します。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-uninstall-package

##Update-Package
- Windows上のVisual StudioのNuGet Package Managerコンソール内でのみ使用できます。
- パッケージとその依存関係、またはプロジェクト内のすべてのパッケージを新しいバージョンに更新します。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-update-package

##Sync-Package
- バージョン3.0+ WindowsのVisual StudioのNuGet Package Managerコンソール内でのみ使用できます。
- 指定された（またはデフォルトの）プロジェクトからインストールされたパッケージのバージョンを取得し、そのバージョンをソリューション内の他のプロジェクトと同期させます。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-sync-package

##Add-BindingRedirect
- Windows上のVisual StudioのNuGet Package Managerコンソール内でのみ使用できます。
- プロジェクトの出力パス内のすべてのアセンブリを調べ、必要に応じてアプリケーションまたはWeb構成ファイルにバインドリダイレクトを追加します。 このコマンドは、パッケージをインストールするときに自動的に実行されます。
- リダイレクトのバインドとその使用の理由の詳細については、.NETドキュメントの「アセンブリバージョンのリダイレクト」を参照してください。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-add-bindingredirect

##Get-Project
- Windows上のVisual StudioのNuGet Package Managerコンソール内でのみ使用できます。デフォルトまたは指定されたプロジェクトに関する情報を表示します。 Get-Projectは、特にプロジェクトのVisual Studio DTE（開発ツール環境）オブジェクトに参照先を返します。
- 3.0以降使用可能

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-get-project

##Open-PackagePage 
- 3.0以降で廃止予定。 WindowsのVisual StudioのNuGet Package Managerコンソール内でのみ使用できます。指定したパッケージのプロジェクト、ライセンス、または不正行為を報告する既定のブラウザを起動します。
- 3.0以降で廃止予定との事でしたが、4.6.0でまだ使用できました。但し、実行時に「Open-PackagePage コマンドは非推奨となり、次のリリースで削除されます。PowerShell スクリプトを適宜変更してください。」の警告メッセージが表示されます。

https://docs.microsoft.com/en-us/nuget/tools/ps-ref-open-packagepage

##Register-TabExpansion
- コマンドのパラメータのタブ展開を登録します。これにより、よく使用されるパラメータ値のカスタマイズされた展開を作成できます。
https://docs.microsoft.com/en-us/nuget/tools/ps-ref-register-tabexpansion
「.bat」のメモ

#★はじめに

ちょうど業務で「.bat」を触る機会がありまして、
今後自分が参照するためのメモとして残しておくことにしました。

#★お試しした内容

ざっくりと一言で言うと、戻り値（errorlevel）についてをお試ししました。

これまでの私の思い込みだったのですが、
コマンドの実行に失敗した場合、errorlevelは必ず**0以外**で戻って来るものだと思っていました。
どうやらそうとも限らないようですね。

普段はerrorlevelでの判定を使用することが多いのですが、
状況によってはerrorlevelを使用していても微妙な感じになってしまうこともあるようです。
コマンドの仕様を調べた訳ではありませんが、お試しした結果を載せていこうと思います。

#####①delで削除に失敗した場合　←後日
#####②ファイルの読み込みに失敗した場合

#★上記の通り失敗させる方法

基本的には、以下の方法を行うようにします。

###その１：ファイルに排他をかておく
エディタの設定を「読み書きを禁止する」に設定して、開いたままにしておく。
<img width="400" alt="スクリーンショット 2018-11-03 16.09.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/eaf80e58-97b4-0be2-494f-4072a96862ad.png">

###その２：ファイルのアクセス権限をなくしておく
ファイルのプロパティで「読み書き禁止」に設定する。
<img width="398" alt="スクリーンショット 2018-11-03 16.39.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/5483a1e6-85dd-1b86-da88-6f55a94f613a.png">

####※読み込み禁止だけでも良いと思います。

#①準備〜結果

　　〜〜編集中〜〜

#②準備〜結果（排他取得時）

・やること
・CSVファイルの中身を読み込むこととする。
<img width="547" alt="スクリーンショット 2018-11-03 16.07.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/4ae8bf05-b901-0d0b-e46f-64f21cef9d8e.png">

#####実行コマンド
・以下のように読み込みを行う。

```bat:test.bat
@echo off

rem 実行前の戻り値
echo %errorlevel%

rem csvファイルから取得した値を変数に設定
set /P EXWORD=<C:\Users\Public\test\test.csv

rem 戻り値出力
echo %errorlevel%

rem 取得した値を出力
echo %EXWORD%

rem ちょっとストップ
pause
```
#####実行結果

別のプロセスが使用中（読み込みには失敗）ですが、戻り値は**０**になりました。
<img width="676" alt="スクリーンショット 2018-11-03 16.32.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/99a625de-81a3-0bc8-ede5-78f677e3f4e6.png">

#③おまけ（アクセス権が無い場合）

#####やること
②と同様。

#####実行コマンド
②と同様。

#####実行結果

アクセスが拒否されていますが、戻り値は**０**になりました。
<img width="567" alt="スクリーンショット 2018-11-03 16.40.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/37e5aae9-42f2-be73-25f6-1ecf02ede532.png">

#おまけ１（普通に実行した場合）

値も取得されています。
<img width="583" alt="スクリーンショット 2018-11-03 16.47.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/bd9e773b-55d4-c0a6-efde-f2d3756b5f74.png">

#おまけ２（同じファイル名のフォルダが存在する場合）
「③おまけ（アクセス権が無い場合）」と同じようになりました。
実行するユーザによって変わるのかな？？
<img width="567" alt="スクリーンショット 2018-11-03 16.40.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/47694/37e5aae9-42f2-be73-25f6-1ecf02ede532.png">

#★さいごに

もし、以上のような条件も考慮する必要があるのであれば、
実行前に変数の値を**""（空）**で初期化しておき、実行後に変数の値が**""（空）**かどうかを判定してあげる必要があるのかなと思いました。

そこまで対応するのかどうかは状況次第ですが、発生することが無いのであれば、
対応しなくても良いかもしれないですね。
オブジェクト指向を3行でまとめ

#背景
- むかし、新人に「オブジェクト指向を一言で言うと何ですか」と質問されたことを思い出した。当時は、何と答えたか忘れたが、今回、改めて、まとめてみようと思う。一言だと、難しいので、3行でまとめます。
- ちなみに、一言だと、「構造化＋＋」かな。

#まとめ
- 構造化設計におけるデータの抽象化の考えを発展させて、｢PC」、「車」というオブジェクト単位のデータ抽象化を指向したものであり、「PC」オブジェクトであれば、それぞれの特徴を持った「Windows PC」、「Mac PC」、「Linux PC」のように具現化可能、「電源ボタンを入れれば、電源が入る」というオブジェクト外部から見える振る舞いを共通化できる。
- オブジェクトの外部へ見えないものを隠蔽化することで、オブジェクトへ命令する事がシンプルに成る。（PCオブジェクトであれば、「電源を入れなさい」というシンプルな命令をするだけで良い。「Windows PCであれば、XXして、YYして電源を入れさせる」、「Mac PCであればAAしてBBして、CCして電源を入れさせる」という細かい命令を伝える必要が無い。）
- 「**カプセル化 (情報隠蔽)**」、「**継承**」、「**ポリモーフィズム (多態性)**」の3つの特徴で表現されることが多い

#最後に
- 「一言で説明して」と言われても、難しいですね。無理に、一言にまとめても伝わらないと思います。
- せめて、「3行で説明して」と言って欲しいですね。
RubyでPyCallを使って形態素解析と機械学習によるニュース記事の分類をしてみる

# はじめに

最近の仕事で「文章を機械学習させる」という案件があり、これまでPythonでは経験があったから、せっかくRubyの街に住んでいるのでRubyでやってみよう...と思いましたが、意外と障壁が高かったのでPyCallを使うことにしました。

「Pythonでやるのと同じじゃないか！」と思われるかもしれませんが、細かなTipsがあるので参考までにまとめておきます。

# ニュース記事の収集

ここでは、"AI"、"IoT"および"Robot"というキーワードで記事データを収集し、それぞれを以下のようにCSV形式で保存したファイルを作ります。
ファイル名は「news.csv」とします。

|分類|記事|
|---|---|
|ai|ビッグデータを分析して...|
|iot|センサーを設置し、温度を...|
|robot|モーターの制御を行う...|
|ai|...|

記事のソースは以下のサイトを参照。

- [CNET Japan](https://japan.cnet.com)
- [IT media](http://www.itmedia.co.jp/news/)
- [日経xTECH](https://tech.nikkeibp.co.jp)

# PyCallのインストール

詳細は以下をご参照下さい。

[GitHub - mrkn/pycall.rb](https://github.com/mrkn/pycall.rb/)

僕は以下のコマンドでインストールしました。

```sh:
sudo gem install pycall       
sudo gem install pandas
```

# Janomeのインストール

Janomeは形態素解析をするPython用のライブラリです。

[GitHub - mocobeta/janome](https://github.com/mocobeta/janome)

僕は以下のコマンドでインストールしました。

```sh:
pip install janome
```

# 記事データの読込

記事データを以下のスクリプトにて読み込みます。

```ruby:
require 'pycall'
require 'pandas'

pd = Pandas

file = "news.csv"
df = pd.read_csv(file)
```

# 形態素解析

以下のスクリプトにて文章を形態素解析により分かち書き文章へ変換します。

```ruby:
tokenizer = PyCall.import_module('janome.tokenizer')
t = tokenizer.Tokenizer.new()

notes = []

df.shape[0].times do |i|
  
  note = df["記事"].iloc[i]
  tokens = t.tokenize(note.gsub('　',' '))
  words = ""
  
  (0..tokens.length - 1).each do |i|
    words += " " + tokens[i].surface
  end
  
  notes << words
  
end
```

# 数値化

分かち書き文章を数値化します。

```ruby:
vectorizer = PyCall.import_module('sklearn.feature_extraction.text')

vect = vectorizer.TfidfVectorizer.new()
vect.fit(notes)

x = vect.transform(notes)
```

分類を数値化します。

```ruby:
labels = ["ai", "iot", "robot"]

y_dic = {}
i = 0

labels.each do |label|
  y_dic[label] = i
  i += 1
end

y = []

df.shape[0].times do |i|
  y << y_dic[df.iloc[i]["分類"]]
end
```

# 機械学習

学習データと検証データの切り分け、学習、テストデータでの精度確認。

```ruby:
model_selection = PyCall.import_module('sklearn.model_selection')

x_train, x_test, y_train, y_test = 
  model_selection.train_test_split(x, y, test_size: 0.1, random_state: 42)

linear_model = PyCall.import_module('sklearn.linear_model')
model = linear_model.LogisticRegression.new()

model.fit(x_train, y_train)

puts model.score(x_test, y_test)
```

僕が集めた記事は、AIが137記事、IoTが134記事、Robotが129記事で、学習精度は0.775でした。
精度が良いのかどうかよくわからない...(-_-;)

# 分類
また、別のサイトから新しい記事を見つけて以下のようにデータ形式をあわせて分類を予測してみる。

```ruby:
text = <<EOF
AI活用の検証から導入、活用までを...
（中略）
...した。
EOF

text.gsub!("\n", "")

texts = [
  text
]

notes = []

texts.each do |note|
  tokens = t.tokenize(note)
  words = ""
  
  tokens.each do |token|
    words += " " + token.surface
  end
  
  notes << words
  
end

x = vect.transform(notes)

result = model.predict(x)

puts labels[result[0].to_i]
```

結果は「ai」でした。

...ということで、できた！