#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""
Explanation: Copyright 2019 The TensorFlow Authors.
End of explanation
"""


!pip install sklearn


import os
import sys

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from six.moves import urllib

"""
Explanation: Estimator で線形モデルを構築する
<table class="tfo-notebook-buttons" align="left">
  <td><a target="_blank" href="https://www.tensorflow.org/tutorials/estimator/linear"><img src="https://www.tensorflow.org/images/tf_logo_32px.png">TensorFlow.org で表示</a></td>
  <td>     <a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/tutorials/estimator/linear.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png">Google Colab で実行</a> </td>
  <td>     <a target="_blank" href="https://github.com/tensorflow/docs-l10n/blob/master/site/ja/tutorials/estimator/linear.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png">GitHub でソースを表示</a> </td>
  <td>     <a href="https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/tutorials/estimator/linear.ipynb"><img src="https://www.tensorflow.org/images/download_logo_32px.png">ノートブックをダウンロード</a> </td>
</table>


警告: 新しいコードには Estimators は推奨されません。Estimators は v1.Session スタイルのコードを実行しますが、これは正しく記述するのはより難しく、特に TF 2 コードと組み合わせると予期しない動作をする可能性があります。Estimators は、互換性保証の対象となりますが、セキュリティの脆弱性以外の修正は行われません。詳細については、移行ガイドを参照してください。

概要
このエンドツーエンドのウォークスルーでは、tf.estimator API を使用してロジスティック回帰モデルをトレーニングします。このモデルはほかのより複雑なアルゴリズムの基準としてよく使用されます。
注意: Keras によるロジスティック回帰の例はこちらからご覧いただけます。これは、本チュートリアルよりも推奨されます。
セットアップ
End of explanation
"""


import tensorflow.compat.v2.feature_column as fc

import tensorflow as tf

# Load dataset.
dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')
dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')
y_train = dftrain.pop('survived')
y_eval = dfeval.pop('survived')

"""
Explanation: Titanic データセットを読み込む
Titanic データセットを使用して、性別、年齢、船室クラスなどの特性に基づき、（やや悪趣味ではありますが）乗船者の生存を予測することを目標とします。
End of explanation
"""


dftrain.head()

dftrain.describe()

"""
Explanation: データを確認する
データセットには、次の特徴が含まれます。
End of explanation
"""


dftrain.shape[0], dfeval.shape[0]

"""
Explanation: トレーニングセットと評価セットには、それぞれ 627 個と 264 個の例があります。
End of explanation
"""


dftrain.age.hist(bins=20)

"""
Explanation: 乗船者の大半は 20 代から 30 代です。
End of explanation
"""


dftrain.sex.value_counts().plot(kind='barh')

"""
Explanation: 男性の乗船者数は女性の乗船者数の約 2 倍です。
End of explanation
"""


dftrain['class'].value_counts().plot(kind='barh')

"""
Explanation: 乗船者の大半は「3 等」の船室クラスを利用していました。
End of explanation
"""


pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')

"""
Explanation: 女性は男性よりも生存する確率がはるかに高く、これは明らかにモデルの予測特徴です。
End of explanation
"""


CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',
                       'embark_town', 'alone']
NUMERIC_COLUMNS = ['age', 'fare']

feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
  vocabulary = dftrain[feature_name].unique()
  feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))

for feature_name in NUMERIC_COLUMNS:
  feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))

"""
Explanation: モデルの特徴量エンジニアリング
Estimator は、モデルがどのように各行の入力特徴量を解釈すべきかを説明する特徴量カラムというシステムを使用しています。Estimator は数値入力のベクトルを期待するのに対し、特徴量カラムはモデルがどのように各特徴量を変換すべきかが記述されています。
効率的なモデルを学習するには、適切な特徴カラムの選択と作成が鍵となります。特徴量カラムは、元の特徴量 dict の生の入力の 1 つ（基本特徴量カラム）または 1 つ以上の基本カラムに定義された変換を使って作成された新規カラム（派生特徴量カラム）のいずれかです。
線形 Estimator は、数値特徴とカテゴリ特徴の両方を利用します。特徴量カラムは TensorFlow Estimator と機能し、その目的はモデリングに使用される特徴量を定義することにあります。さらに、One-Hotエンコーディング、正規化、およびバケット化などのいくつかの特徴量エンジニアリング機能を提供します。
基本特徴量カラム
End of explanation
"""


def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
  def input_function():
    ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))
    if shuffle:
      ds = ds.shuffle(1000)
    ds = ds.batch(batch_size).repeat(num_epochs)
    return ds
  return input_function

train_input_fn = make_input_fn(dftrain, y_train)
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)

"""
Explanation: input_function は、入力パイプラインをストリーミングの手法でフィードする tf.data.Dataset にデータを変換する方法を指定します。tf.data.Dataset は、dataframe や csv 形式ファイルなど、複数のソースを取ることができます。
End of explanation
"""


ds = make_input_fn(dftrain, y_train, batch_size=10)()
for feature_batch, label_batch in ds.take(1):
  print('Some feature keys:', list(feature_batch.keys()))
  print()
  print('A batch of class:', feature_batch['class'].numpy())
  print()
  print('A batch of Labels:', label_batch.numpy())

"""
Explanation: 次のようにデータセットを検査できます。
End of explanation
"""


age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()

"""
Explanation: また、tf.keras.layers.DenseFeatures レイヤーを使用して、特定の特徴量カラムの結果を検査することもできます。
End of explanation
"""


gender_column = feature_columns[0]
tf.keras.layers.DenseFeatures([tf.feature_column.indicator_column(gender_column)])(feature_batch).numpy()

"""
Explanation: DenseFeatures は密なテンソルのみを受け入れ、それを最初にインジケータカラムに変換する必要のあるカテゴリカラムを検査します。
End of explanation
"""


linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)

"""
Explanation: すべての基本特徴量をモデルに追加したら、モデルをトレーニングすることにしましょう。モデルのトレーニングは、 tf.estimator API を使ってコマンド 1 つで行います。
End of explanation
"""


age_x_gender = tf.feature_column.crossed_column(['age', 'sex'], hash_bucket_size=100)

"""
Explanation: 派生特徴量カラム
精度が 75% に達しました。それぞれの基本特徴量カラムを個別に使用しても、データを説明するには不足している場合があります。たとえば、年齢とラベルの間の相関関係は、性別が変われば異なることがあります。そのため、gender="Male" と gender="Female" で単一モデルの重みのみを把握しただけでは、すべての年齢と性別の組み合わせをキャプチャすることはできません（gender="Male" と age="30" と gender="Male" と age="40" を区別するなど）。
さまざまな特徴量の組み合わせの間の違いを把握するには、相互特徴量カラムをモデルに追加できます（また、相互カラムの前に年齢カラムをバケット化できます）。
End of explanation
"""


derived_feature_columns = [age_x_gender]
linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns+derived_feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)

"""
Explanation: 組み合わせた特徴量をモデルに追加したら、モデルをもう一度トレーニングしましょう。
End of explanation
"""


pred_dicts = list(linear_est.predict(eval_input_fn))
probs = pd.Series([pred['probabilities'][1] for pred in pred_dicts])

probs.plot(kind='hist', bins=20, title='predicted probabilities')

"""
Explanation: これで、77.6% の精度に達しました。基本特徴量のみでトレーニングした場合よりわずかに改善されています。ほかの特徴量と変換を使用して、さらに改善されるか確認してみましょう！
このトレーニングモデルを使用して、評価セットからある乗船者に予測を立てることができます。TensorFlow モデルは、バッチ、コレクション、または例に対してまとめて予測を立てられるように最適化されています。以前は、eval_input_fn は評価セット全体を使って定義されていました。
End of explanation
"""


from sklearn.metrics import roc_curve
from matplotlib import pyplot as plt

fpr, tpr, _ = roc_curve(y_eval, probs)
plt.plot(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('false positive rate')
plt.ylabel('true positive rate')
plt.xlim(0,)
plt.ylim(0,)

"""
Explanation: 最後に、結果の受信者操作特性（ROC）を見てみましょう。真陽性率と偽陽性率間のトレードオフに関し、より明確な予想を得ることができます。
End of explanation
"""


