train_test_split()関数の使い方について
train_test_split
【目次】
【動作環境】
1. train_test_splitについて
データセットや配列を訓練データとテストデータに分割するための関数。
- 訓練データ:モデル構築のために必要なデータ。任意のモデルで学習させ、モデルを構築(方程式)する。一般的には、X_train, y_trainで定義することが多い。
- テストデータ:構築したモデルを使用して、説明変数から目的変数を算出するためのデータ。算出した目的変数と、テストデータの目的変数(正解ラベル)を比較して、構築したモデルがどれくらい適切なモデルなのかを評価する。一般的には、X_test, y_testで定義することが多い。
2. train_test_splitの使い方
2.1. train_test_splitの基本
以下の挙動確認用データを作っておく。
import numpy as np from sklearn.model_selection import train_test_split X, y = np.arange(10).reshape((5, 2)), range(5) print('Xのデータ:\n', X, '\n') #\nは改行コード print('yのデータ:\n', y, '\n') #\nは改行コード
>> Xのデータ:
>> [[0 1]
>> [2 3]
>> [4 5]
>> [6 7]
>> [8 9]]
>> yのデータ:
>> range(0, 5)
これらのX, yデータに対しtrain_test_split()関数を用いて、訓練データとテストデータに分割する。
左辺は下記の並びにするのが一般的(訓練X→テストX→訓練y→テストy)。
右辺は第一引数及び第二引数に分割したいデータを並べる。
一般には、説明変数→目的変数の順で並べるのが一般的。
X_train, X_test, y_train, y_test = train_test_split(X, y) print('X_trainのデータ:\n', X_train, '\n') print('X_testのデータ:\n', X_test, '\n') print('y_trainのデータ:\n', y_train, '\n') print('y_testのデータ:\n', y_test, '\n')
>> X_trainのデータ:
>> [[0 1]
>> [8 9]
>> [2 3]]
>> X_testのデータ:
>> [[4 5]
>> [6 7]]
>> y_trainのデータ:
>> [0, 4, 1]
>> y_testのデータ:
>> [2, 3]
random_stateを何も指定しない場合(デフォルト値)は、Noneとなる(実行毎に分割されるデータが変わる)。
また、この時分割されるtrainとtestの比率は別のオプションのtest_size、train_sizeで指定可能だが、何も指定しない上記の場合(デフォルト値)は、test_size=0.25(訓練データ:0.75、テストデータ:0.25)となる。
2.2. random_stateで乱数シードを指定
test_sizeオプションで変えることが可能
test_sizeは、切り上げで指定可能である。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42) print('X_trainのデータ:\n', X_train, '\n') print('X_testのデータ:\n', X_test, '\n') print('y_trainのデータ:\n', y_train, '\n') print('y_testのデータ:\n', y_test, '\n')
>> X_trainのデータ:
>> [[4 5]
>> [0 1]
>> [6 7]]
>> X_testのデータ:
>> [[2 3]
>> [8 9]]
>> y_trainのデータ:
>> [2, 0, 3]
>> y_testのデータ:
>> [1, 4]
実行毎に分割されるデータが変わることはない。
2.3. 訓練データとテストデータの比率を変える
test_sizeオプションで変えることが可能
test_sizeは、小数点以下2桁目にて、切り上げで指定可能である。
以下は、訓練データ:0.60、テストデータ:0.40で分割した例
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.40, random_state=42) print('X_trainのデータ:\n', X_train, '\n') print('X_testのデータ:\n', X_test, '\n') print('y_trainのデータ:\n', y_train, '\n') print('y_testのデータ:\n', y_test, '\n')
>> X_trainのデータ:
>> [[4 5]
>> [0 1]
>> [6 7]]
>> X_testのデータ:
>> [[2 3]
>> [8 9]]
>> y_trainのデータ:
>> [2, 0, 3]
>> y_testのデータ:
>> [1, 4]
訓練データが3つ、テストデータが2つで分けられている。
今度は、以下は、訓練データ:0.59、テストデータ:0.41で分割した例
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.40, random_state=42) print('X_trainのデータ:\n', X_train, '\n') print('X_testのデータ:\n', X_test, '\n') print('y_trainのデータ:\n', y_train, '\n') print('y_testのデータ:\n', y_test, '\n')
>> X_trainのデータ:
>> [[0 1]
>> [6 7]]
>> X_testのデータ:
>> [[2 3]
>> [8 9]
>> [4 5]]
>> y_trainのデータ:
>> [0, 3]
>> y_testのデータ:
>> [1, 4, 2]
訓練データが2つ、テストデータが3つで分けられる結果に変わった(小数点以下2桁目にて、切り上げされて算出される)。
【参照】
sklearnで学習を進めるにあたって、知っておくべきメモ
【目次】
- 1. sklearnのDatasetsを使った学習にあたって
- 2. sklearnで用意されているDatasets
- 3. Datasetsの中身をのぞいてみる(load_iris)
- 3.1. load_irisの全体像
- 4. データを読みやすくする
【動作環境】
1. sklearnのDatasetsを使った学習にあたって
sklearnの学習に突入した時最初に思ったのは、sklearnのdatasetsってどんな様式になっているのだろうかと思った。
参考書を通して目的変数、説明変数も理解できて、sklearnのデータの内容も何となくわかったけど、いざプログラムでデータを読み出した時、どこに何のデータが隠れているのか全く読むことができず、再現性のあるスキル習得ができなかったのではないかと感じた。
今となっては、大丈夫だが学習効率の面で少々ロスしたのかもしれない。
そもそも使っているデータセットの見方がわからないと、機械学習の方法論だけなんとなく理解して、「結局、今やったデータの解釈とは?...」という状況になりかねない。
データ分析で必要なことは分析手法を多く知っている事も重要であるが、分析した結果を適切に理解して次のアクションにつなげることが最も大事であると思っている。
結局のところ、実際の仕事ではcsv等のファイルを読み込むことになるので、sklearn datasetsの把握にはあまり時間を割かないでも良いと思うが、個人的な経験上、学習効率が悪くなったの思うので、必要最低限のことをメモしておく。
2. sklearnで用意されているDatasets
2.1. Datasetsの種類
以下のリンクにsklearnで使用可能なdatasetsの一覧が用意されている。
Loaders datasets.clear_data_home([data_home]) Delete all the content of the data home cache. datasets.dump_svmlight_file(X, y, f, *[, …]) Dump the dataset in svmlight / libsvm file format. datasets.fetch_20newsgroups(*[, data_home, …]) Load the filenames and data from the 20 newsgroups dataset (classification). datasets.fetch_20newsgroups_vectorized(*[, …]) Load the 20 newsgroups dataset and vectorize it into token counts (classification). datasets.fetch_california_housing(*[, …]) Load the California housing dataset (regression).
API Reference — scikit-learn 0.23.1 documentation
左側には呼出方法、右側にはDatasetsの説明が記載してある。
Datasetsには括弧書きでどのような目的で使用するのか、の補足が記載されているものもある。
主に2つ把握しておけばOK。
- 回帰(regression)
- クラスタリング(classification)
3. Datasetsの中身をのぞいてみる(load_iris)
アヤメの花のDatasetsを例にとって確認してみる。
3.1. load_irisの全体像
Referenceの最初には以下の情報がある。
Classes 3 Samples per class 50 Samples total 150 Dimensionality 4 Features real, positive
1クラス50個のデータが3クラス存在していて、合計150個のデータが存在している。
Dimensionality(次元)がデータの種類数。それぞれのデータは4つの説明変数があるという事。
3.2. Datasetsの中身(load_iris)
以下のコードでdataの内容確認が可能。
from sklearn.datasets import load_iris iris = load_iris() iris
出力結果詳細は省略するが、以下の値が出力される。
* feature_names: dataを説明する名称
* data: data。説明変数となるデータ
* target_names: 目的変数を説明する名称
* target: 目的変数となるデータ
* DESCR:データの詳細
* filename:sklearnのdatasetsの格納場所がある。実はcsvファイルであることがわかる
ここで、以下の問題が出てくる。
- DESCRについて、改行が無視されているので読みにくい
- data(説明変数)とtarget(目的変数)の関係性がわかりにくい。
そこで、以下の方法でデータを読みやすくする。
4. データを読みやすくする
4.1. Datasetsの中身(load_iris)
irisデータに対して、DESCRを指定する事で詳細のみを表示させることが可能。
from sklearn import datasets iris = datasets.load_iris() print(iris.DESCR)
4.2. pandasのDataFrame形式に変換する
pandasのDataFrameを利用する。
columnsに、dataのラベルとなる「feature_names」を指定する。
もう一つ列を増やし、各データの目的変数として「iris.target」を指定する。
import pandas as pd from sklearn.datasets import load_iris iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) iris_df['class'] = iris.target iris_df.sample(5, random_state=1)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | class | |
---|---|---|---|---|---|
14 | 5.8 | 4.0 | 1.2 | 0.2 | 0 |
98 | 5.1 | 2.5 | 3.0 | 1.1 | 1 |
75 | 6.6 | 3.0 | 4.4 | 1.4 | 1 |
16 | 5.4 | 3.9 | 1.3 | 0.4 | 0 |
131 | 7.9 | 3.8 | 6.4 | 2.0 | 2 |
classを0〜2で表現しているが、それぞれが何に該当するのかをデータに入れてみても良いと思われる。
import pandas as pd from sklearn.datasets import load_iris iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) iris_df['species'] = [iris.target_names[i] for i in iris.target] iris_df.sample(5, random_state=1)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | species | |
---|---|---|---|---|---|
14 | 5.8 | 4.0 | 1.2 | 0.2 | setosa |
98 | 5.1 | 2.5 | 3.0 | 1.1 | versicolor |
75 | 6.6 | 3.0 | 4.4 | 1.4 | versicolor |
16 | 5.4 | 3.9 | 1.3 | 0.4 | setosa |
131 | 7.9 | 3.8 | 6.4 | 2.0 | virginica |
このようにして、DataFrame形式で可視化する事で少々データがみやすくなったのではないかと思う。
あまりきれいでないcsvファイルを取り扱う時、一度DataFrame形式hへ変換してデータの内容をしっかりと把握するのもてだと感じる。
pandasにおけるsample()の使い方
【目次】
【動作環境】
1. sample()について
pandasのDataFrameにおいて、ランダムに行を抽出することが可能。
2. 挙動テスト
サンプルデータ。panda形式のDataFrameを用意する。
df = pd.DataFrame({'num_legs': [2, 4, 8, 0], 'num_wings': [2, 0, 0, 0], 'num_specimen_seen': [10, 2, 1, 8]}, index=['falcon', 'dog', 'spider', 'fish']) df
num_legs | num_wings | num_specimen_seen | falcon |
---|---|---|---|
falcon | 2 | 2 | 10 |
dog | 4 | 0 | 2 |
spider | 8 | 0 | 1 |
fish | 0 | 0 | 8 |
- 単に2行抽出したい時
df.sample(2)
num_legs | num_wings | num_specimen_seen | falcon |
---|---|---|---|
spider | 8 | 0 | 1 |
fish | 0 | 0 | 8 |
実行の度に抽出される行が変わることに注意。
1回目実行時は「spider」と「fish」の2行が抽出されたが、2回目以降は別な2行が再度ランダム選定される。
- 単に2行抽出したい時(random_state指定あり)
データ分析で再現性を確認する時に、データの前提条件が実行単位で変わると不便なので、ランダムで行を抽出しつつも実行単位ではばらつきをなくすようにする。
そこで登場するのがrandom_state object(Numpy)。
ランダムで抽出する際に、実行毎に固定の値を算出。いくつかのパターンを設ける目的で、数値を指定可能(以下は1を指定した時)。
numpy.random.RandomState — NumPy v1.15 Manual
df.sample(n=2, random_state=1)
num_legs | num_wings | num_specimen_seen | falcon |
---|---|---|---|
fish | 0 | 0 | 8 |
spider | 8 | 0 | 1 |
何回実行しても、。「fish」と「dog」が抽出される。
【参照】
Python range() 関数 メモ
関数のメモ
基本的なことだが、挙動が気になったので細かく書いてみる。
【目次】
【動作環境】
1. range()関数の定義
内容:特定の数値の範囲を表し、loop処理に用いられる。typeはrangeとなる。
class range(start, stop[, step])
- start:初期値 (省略可。デフォルトは0)
- stop:終了値
- step:ステップ(省略可)
2. 挙動テスト
以下、挙動テストのため流し見推奨。
- 挙動テスト1
print(type(range(2,3)))
>> class 'range'
typeはrangeというtypeでそのまま出てくる。
- 挙動テスト2
print(range(3)) print(range(6)) print(range(100))
>> range(0, 3)
>> range(0, 6)
>> range(0, 100)
range形式でそのまま表示される。startを省略すると、初期値は常に0。
- 挙動テスト3
range(1, 3) range(1, 6) range(1, 100,2)
>> range(1, 3)
>> range(1, 6)
>> range(1, 100,2)
初期値を1にしてみる。stepを変えてみても表示は同様。
3. 使用例
- 1〜20までの奇数をrangeを、変数varに格納してみる。
var = range(1, 20, 2) for num in var: print(num)
>> 1
>> 3
>> 5
>> 7
>> 9
>> 11
>> 13
>> 15
>> 17
>> 19
- 1〜20までの偶数をrangeを変数に格納する
var = range(2, 20, 2) for num in var: print(num)
>> 2
>> 4
>> 6
>> 8
>> 10
>> 12
>> 16
>> 18
>> 20
【参照】
暗号化技術 ざっくりまとめ
目次
昨今の科学技術の発達により、暗号化技術は進化を遂げてきた。
ここでは、昔使用されていた単純な暗号化アルゴリズムのことを古典的な暗号と表現する。
現代の暗号化技術はネットワークのセキュリティに応用されているが、
暗号化方式には、共通鍵暗号化方式と公開鍵暗号化方式に分けることができる。
また、一般的には暗号化される前のデータを「平文」(ひらぶん)と呼ぶ。
古典的な暗号
古典的な暗号には、シーザー暗号やバーナム暗号が存在する。
- シーザー暗号
送信したいメッセージに対して、アルファベットをx文字のみずらしてメッセージを送信する暗号化技術。
例えば、「book」というメッセージに対して、3文字ずつずらしたシーザー暗号を作ると「errn」という暗号文が出来上がる。
- バーナム暗号
ビット列に変換した平文と、ビット列に変換した乱数を足し合わせて暗号文を作ること。
(ビット列に変換とは、2進数表記に変換すること)
例えば、「set」という平文を、下記のように暗号化すると暗号文が完成する。
元の平文 | ASCIIコードで符号化した平文 | 平文をビット列に変換 | + | 暗号化鍵(乱数) | = | 暗号文 |
---|---|---|---|---|---|---|
s | 73 | 01110011 | + | 11100111 (E7) | = | 10010100 (94) |
e | 65 | 01100101 | + | 01001111 (4F) | = | 00101010 (2A) |
t | 74 | 01110100 | + | 10110110 (B6) | = | 11000010 (C2) |
この手法は毎回乱数が変わっていくので理論的には解読不可となる。
要するに、Brute Force Attack(総当たり攻撃)でも暗号化鍵が見つからないほど強固な方法である。
しかし、問題点として、
- 1 . 暗号化鍵配送の問題:2者間で乱数を共有しておく必要があるので、秘密裏に暗号化鍵(乱数)を届ける必要がある。
- 2 . 暗号化鍵を再利用できない:暗号文を復号するヒントを与えてしまう。
- 3 . 乱数列作成の困難性:コンピュータで乱数を作成すると、一定の規則性が生まれたり一定間隔で同じ値が生成されてしまう。
そこで、現代の暗号化技術に繋がってくる。
共通鍵暗号化方式
秘密を共有したい2者間で同じ鍵を使う方式。
鍵は他者に漏れないようにする。
共通鍵暗号化技術は、ブロック暗号化方式とストリーム暗号化方式に別れる。
- ブロック暗号化方式
データ攪拌部と鍵生成部とから構成され、暗号化をブロック単位で行う。 DESやAESのような方式がある。
- ストリーム暗号化方式
擬似乱数生成器が生成する乱数を使い、入力された平文をビット単位で暗号化する。
RC4のような方式がある。
公開鍵暗号化方式
暗号化する鍵(公開鍵)と復号する鍵とが異なる暗号化方式。
暗号化する鍵は、不特定多数の人に配る。復号する鍵は誰にも知られてはならない。
暗号化する鍵を用いて特定の文字列を暗号化し、復号する鍵(秘密鍵)を用いて暗号化された文字列を復号する。
例えば、メッセージの送信者をA、メッセージの受信者をBとすると、Aは公開されている暗号化する鍵(公開鍵)を用いてメッセージ(平文)を暗号化する。
Aは暗号化されたメッセージをBに送信する。Bは秘密鍵を用いて暗号化された文字列を復号する。
主な暗号化方式
共通鍵暗号化方式 | 概要 |
---|---|
DES(Data Encryption Standard) | 64ビット(8ビットはパリティービット(区切りのためのビット)のため、有効鍵長は56ビット)のブロック単位で平文を暗号化する。その組み合わせは、2の56乗(約7.2京)であるが、1999年に22時間で破られたり、線形解読法などの理論も登場してきたことから、安全性が問題視されて利用を避けることになっている。 |
3DES(triple-DES) | DESを3回(暗号化→復号→暗号化)を行うことで暗号強度を高めた暗号化方式。3-key方式と、2-key(1回目と3回目の暗号鍵は同じ)がある。 |
AES(Adverse Encryption Standard) | 128ビット長のブロック暗号化方式。鍵長は128、192、256ビットの3種類ある。2013年時点では安全とされており、利用が推奨されいている。 |
RC4 | 鍵長が可変(40〜256ビット)の方式。Web通信の暗号化のためのSSL/TLS、無線LANのWEPで使用されている。3DESに比べて高速に計算可能だが、AESと比較すると同程度の処理速度であるため、優位性は低下している。 |
公開鍵鍵暗号化方式 | 概要 |
---|---|
RSA暗号 | 巨大な素数の素因数分解が困難なこと(暗号鍵に不可逆性がある)を安全性の根拠とした暗号化アルゴリズム。その安全性はDESのおよそ100倍の処理速度を要すると言われている。逆の仕組みを応用してデジタル署名技術にも応用されている。 |
楕円曲線暗号(ECC) | 楕円曲線上の離散対数問題の困難さを安全性の根拠としたもの。ECDSA(Elliptic Curve Digital Signiture Algolithm)と呼ばれるデジタル署名用アルゴリズムに応用されている。RSAと比較してデジタル署名の処理速度が早いことが特徴。 |
ハイブリッド暗号
RSA暗号は鍵長が長いと処理速度が遅くなるというデメリットがある。
要するに、送信したいメッセージが長ければ長いほど処理速度が低下するという問題が発生する。
そこで、AESなどの共通鍵暗号方式との組み合わせを行うことで、早い処理速度を維持したまま安全性の高い通信を行うことができる。
具体的には、共通鍵暗号の共通鍵にあたる部分のみをRSAで暗号化を行い、通信したい相手に対して共通鍵を安全に送信することが可能。
互いのメリットを活かし、デメリットを相殺するような仕組みが取られている。
最後に、様々な暗号化手法が確立されているが、安全性を検証したものでないと実用的に使用することはできない。
(自分で勝手に作った暗号は検証さレていないので、セキュリティの観点上リスクがある。)
【参照】
python_webbrowserモジュール
webbrowserモジュールとは? 新たにブラウザを起動して、URLを開くモジュールのこと。 open()関数で開くことができる。
1. 基本的な使い方
open()関数を使用して特定のURLを開く。()内にURLをシングルクオテーション区切りで指定
import webbrowser webbrowser.open('http://www.python.org')
>> (新しいタブで開かれた)
open_new/open_new_tab関数も同様に使用可能。
2. 環境名取得
get関数を用いて、開くブラウザの環境名を取得することができる。 ()内に環境名を指定することも可能。
import webbrowser
webbrowser.get()
>>webbrowser.MacOSXOSAScript a XXXXXXXX (Mac環境では上記の表示になった) XXXXXXXXには、デフォルト(カッコ内がnoneの時)ブラウザのコントローラ名を返している。 get関数の()内にブラウザ名などを指定すると、XXXXXXXXに違う文字列が表示されたりもする。
【参照】
Al Sweigart. 退屈なことはpython にやらせよう. 株式会社オライリー・ジャパン, 2019, 562p