那須野薫(Kaoru Nasuno)/ 東京大学(The University of Tokyo)
データサイエンスの基礎的なスキルを身につける為のチュートリアルです。
KaggleのコンペティションであるRECRUIT Challenge, Coupon Purchase Predictionのデータセットを題材として、
データサイエンスの基礎的なスキルに触れ,理解の土台を養うことを目的とします。
(高い予測精度を出すことが目的ではないです)
まだ、書きかけでして、要望に合わせて誤りの修正や加筆をしていく予定です。何かお気づきの点があればご連絡頂けますと幸いです。
RECRUIT Challenge, Coupon Purchase Predictionのデータセット。
ユーザ登録や利用規約に同意してダウンロードしてください。
https://www.kaggle.com/c/coupon-purchase-prediction/data
まずは、全てのコードをコピー&ペーストして、エラーなく動作することを確認しましょう。
この段階でエラーが出る場合には環境が整っていないか、パラメタの設定ができていない等、
プログラムの理解とはあまり関係のない箇所が原因である可能性が高いです。
動作確認が終わったら、ひとつずつ書き写してみて、それぞれどのように動作するかを理解していくという方法をお勧めします。
1, 2 について進めていきます。 3. 以降については、Lecture 02以降を参照ください。
brew update;
pip install ipython;
pip install ipython[notebook];
brew install mariadb;
pip install MySQL-python;
pip install scikit-learn;
mysqlが起動していない場合は、下記のコマンドでmysqlのプロセスを立ち上げましょう。
mysqld_safe;
MySQLクライアンの一つであるSequel Pro( http://www.sequelpro.com/ )もinstall してください。
このチュートリアルではMySQL(MariaDB)というリレーショナルデータベースを利用します。
ここでは、利用するデータベース名をcoupon_purchaseとし、データベースを作成していない人は下記のコマンドをターミナルで実行してください。
echo 'CREATE DATABASE coupon_purchase; ' |mysql -uroot
rootユーザのパスワードを設定している方は
echo 'CREATE DATABASE coupon_purchase; ' |mysql -uroot -pyourpassword
としてください。
ローカル環境下で実行している場合には、sequel proで下記のような設定で
でデータベースにアクセスできるようになっているはずです。
(MySQLのパスワードを設定していない場合には、パスワード欄は空白)
以下は、ipython notebook上で実行してください。
ipython notebook は下記のコマンドをターミナルで実行することで起動できます。
ipython notebook;
起動すると、ブラウザ上でipython notebookが起動します。
New >> python2(or New Notebook)をクリックすることで、新しいpythonのノートブックを作成できます。
MySQLのユーザ名やパスワードなどのパラメタを指定してください。
多くの場合はuser
やpasswd
を変更すれば動くと思います。
また、ダウンロードし、解凍した9つのcsvファイルが置いてあるディレクトリのパスを設定してください。
(coupon_area_test.csv, coupon_list_test.csv, prefecture_locations.csv, coupon_area_train.csv, coupon_list_train.csv, sample_submission.csv, coupon_detail_train.csv, coupon_visit_train.csv user_list.csv)
In [1]:
# TODO: You Must Change the setting bellow
MYSQL = {
'user': 'root',
'passwd': '',
'db': 'coupon_purchase',
'host': '127.0.0.1',
'port': 3306,
'local_infile': True,
'charset': 'utf8',
}
DATA_DIR = '/home/nasuno/recruit_kaggle_datasets' # ディレクトリの名前に日本語(マルチバイト文字)は使わないでください。
OUTPUTS_DIR = '/home/nasuno/recruit_kaggle/outputs' # 予測結果などを保存するディレクトリ。
In [2]:
%matplotlib inline
import matplotlib.pyplot as plt
import MySQLdb
import numpy
from sklearn.utils import shuffle
from sklearn.cross_validation import train_test_split
from sklearn.metrics import f1_score, accuracy_score
from sklearn.linear_model import LogisticRegression
from datetime import datetime, timedelta
from itertools import product
# Random Seed
rng = numpy.random.RandomState(1234)
dbcon = MySQLdb.connect(**MYSQL)
dbcur = dbcon.cursor()
データベースとは、色々なデータの目的ベースでの管理や、効率的なデータ参照/検索を可能にするものです。
データベースの中には複数のテーブルがあります。
テーブルはちょうどスプレッドシートのようになっていて、それぞれの列に名前があり、1行が1つのデータとなるイメージです。
データの格納の流れは大まかに、
の3つのステップとなります。
kaggleのページにテーブルの定義が書いてあるので、ここでは、その通りに作成します。
まずは、user_listのテーブル作成クエリと実行です。
MySQLのCREATE TABLE構文については、http://dev.mysql.com/doc/refman/5.6/ja/create-table.html を参照ください。
In [3]:
dbcur.execute('''DROP TABLE IF EXISTS user_list;''') # チュートリアルの便宜上、一度削除します。
query = '''
CREATE TABLE IF NOT EXISTS user_list (
reg_date DATETIME,
sex_id VARCHAR(1),
age INT,
withdraw_date DATETIME,
pref_name VARCHAR(15),
user_id_hash VARCHAR(32),
PRIMARY KEY(user_id_hash),
INDEX(reg_date),
INDEX(sex_id),
INDEX(age),
INDEX(withdraw_date),
INDEX(pref_name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
'''
dbcur.execute(query)
Out[3]:
次に、データのインサートです。
csvファイルなど、dumpされたファイルからMySQLにインサートする場合にはLOAD DATA INFILE構文を利用します。
LOAD DATA INFILE構文については、 http://dev.mysql.com/doc/refman/5.6/ja/load-data.html を参照ください。
In [4]:
csv_path = DATA_DIR + '/user_list.csv'
query = '''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE user_list
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(reg_date, sex_id, age,@withdraw_date, pref_name, user_id_hash)
SET
withdraw_date = IF(CHAR_LENGTH(@withdraw_date) != 19 , '9999-12-31 23:59:59', STR_TO_DATE(@withdraw_date, "%Y-%m-%d %H:%i:%s"))
;
'''
dbcur.execute(query)
Out[4]:
テーブルの作成に利用したCREATE TABLE文には、
テーブルの型の定義ではなく、インデックスと呼ばれるものの定義も含まれています。
インデックスとはデータの検索を高速化するものです。
テーブル内でuniqueで、かつ、検索するカラムに付与する。 例えば、user_listテーブルのuser_id_hashは当該テーブルで、ユニークであり,かつ、ユーザの検索によく用いるため、PRIMARY KEYを付与しておいた方が良い。
テーブル内でuniqueではないが、検索するカラムに付与する。例えば、ユーザを性別や年齢に応じて検索・集計して、割合を見たい場合には、sex_idやageなどのカラムに付与しておいた方が良い。
MYSQL関数などの説明の加筆。
下記の他のファイルについても同様にテーブルを作成し、データをインサートしてください。
In [5]:
### prefecture_locations
csv_path = DATA_DIR + '/prefecture_locations.csv'
dbcur.execute('''DROP TABLE IF EXISTS prefecture_locations;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS prefecture_locations (
pref_name VARCHAR(15),
PRIMARY KEY(pref_name),
prefectual_office VARCHAR(15),
latitude DOUBLE,
longitude DOUBLE
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE prefecture_locations
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(pref_name, prefectual_office, latitude, longitude)
;
''')
Out[5]:
実行すると、それぞれのレコードでWarningが発生しますが、
データベースに展開されたレコードのlongitudeを確認すると正しく展開されているため、ここではWarningは無視します。
(確認しておりませんが、行末の改行コードがWarningの原因かもしれません、、、)
In [6]:
### coupon_area_train
csv_path = DATA_DIR + '/coupon_area_train.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_area_train;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_area_train (
small_area_name VARCHAR(32),
pref_name VARCHAR(15),
coupon_id_hash VARCHAR(32),
INDEX(coupon_id_hash),
INDEX(pref_name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_area_train
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(small_area_name,pref_name,coupon_id_hash)
;
''')
Out[6]:
In [7]:
### coupon_area_test
csv_path = DATA_DIR + '/coupon_area_test.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_area_test;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_area_test (
small_area_name VARCHAR(32),
pref_name VARCHAR(15),
coupon_id_hash VARCHAR(32),
INDEX(coupon_id_hash),
INDEX(pref_name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_area_test
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(small_area_name,pref_name,coupon_id_hash)
;
''')
Out[7]:
In [8]:
### coupon_detail_train
csv_path = DATA_DIR + '/coupon_detail_train.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_detail_train;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_detail_train (
item_count INT,
i_date DATETIME,
small_area_name VARCHAR(32),
purchaseid_hash VARCHAR(32),
user_id_hash VARCHAR(32),
coupon_id_hash VARCHAR(32),
INDEX(coupon_id_hash)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_detail_train
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(item_count, i_date, small_area_name, purchaseid_hash, user_id_hash, coupon_id_hash)
;
''')
Out[8]:
In [9]:
### coupon_visit_train
csv_path = DATA_DIR + '/coupon_visit_train.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_visit_train;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_visit_train (
purchase_flg INT,
i_date DATETIME,
page_serial INT,
referrer_hash VARCHAR(128),
view_coupon_id_hash VARCHAR(128),
user_id_hash VARCHAR(32),
session_id_hash VARCHAR(128),
purchaseid_hash VARCHAR(32),
INDEX(user_id_hash, i_date),
INDEX(i_date, user_id_hash),
INDEX(view_coupon_id_hash),
INDEX(purchaseid_hash),
INDEX(purchase_flg)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_visit_train
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(purchase_flg,i_date,page_serial,referrer_hash,view_coupon_id_hash,user_id_hash,session_id_hash,purchaseid_hash)
;
''')
Out[9]:
SET validperiod=IF(@validperiod = 'NA', Null, @validperiod)
In [10]:
### coupon_list_train
csv_path = DATA_DIR + '/coupon_list_train.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_list_train;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_list_train (
capsule_text VARCHAR(20),
genre_name VARCHAR(50),
price_rate INT,
catalog_price INT,
discount_price INT,
dispfrom DATETIME,
dispend DATETIME,
dispperiod INT,
validfrom DATE,
validend DATE,
validperiod INT,
usable_date_mon VARCHAR(7),
usable_date_tue VARCHAR(7),
usable_date_wed VARCHAR(7),
usable_date_thu VARCHAR(7),
usable_date_fri VARCHAR(7),
usable_date_sat VARCHAR(7),
usable_date_sun VARCHAR(7),
usable_date_holiday VARCHAR(7),
usable_date_before_holiday VARCHAR(7),
large_area_name VARCHAR(30),
ken_name VARCHAR(8),
small_area_name VARCHAR(30),
coupon_id_hash VARCHAR(32),
PRIMARY KEY(coupon_id_hash),
INDEX(ken_name),
INDEX(genre_name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_list_train
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(capsule_text,genre_name,price_rate,catalog_price,discount_price,dispfrom,dispend,dispperiod,validfrom,validend,@validperiod,usable_date_mon,usable_date_tue,usable_date_wed,usable_date_thu,usable_date_fri,usable_date_sat,usable_date_sun,usable_date_holiday,usable_date_before_holiday,large_area_name,ken_name,small_area_name,coupon_id_hash)
SET validperiod=IF(@validperiod = 'NA', Null, @validperiod)
;
''')
Out[10]:
In [11]:
### coupon_list_test
csv_path = DATA_DIR + '/coupon_list_test.csv'
dbcur.execute('''DROP TABLE IF EXISTS coupon_list_test;''')
dbcur.execute('''
CREATE TABLE IF NOT EXISTS coupon_list_test (
capsule_text VARCHAR(20),
genre_name VARCHAR(50),
price_rate INT,
catalog_price INT,
discount_price INT,
dispfrom DATETIME,
dispend DATETIME,
dispperiod INT,
validfrom DATE,
validend DATE,
validperiod INT,
usable_date_mon VARCHAR(7),
usable_date_tue VARCHAR(7),
usable_date_wed VARCHAR(7),
usable_date_thu VARCHAR(7),
usable_date_fri VARCHAR(7),
usable_date_sat VARCHAR(7),
usable_date_sun VARCHAR(7),
usable_date_holiday VARCHAR(7),
usable_date_before_holiday VARCHAR(7),
large_area_name VARCHAR(30),
ken_name VARCHAR(8),
small_area_name VARCHAR(30),
coupon_id_hash VARCHAR(32),
PRIMARY KEY(coupon_id_hash),
INDEX(ken_name),
INDEX(genre_name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
;
''')
dbcur.execute('''
LOAD DATA LOCAL INFILE "''' + csv_path + '''"
INTO TABLE coupon_list_test
CHARACTER SET utf8
FIELDS TERMINATED BY ','
IGNORE 1 LINES
(capsule_text,genre_name,price_rate,catalog_price,discount_price,dispfrom,dispend,dispperiod,validfrom,validend,@validperiod,usable_date_mon,usable_date_tue,usable_date_wed,usable_date_thu,usable_date_fri,usable_date_sat,usable_date_sun,usable_date_holiday,usable_date_before_holiday,large_area_name,ken_name,small_area_name,coupon_id_hash)
SET validperiod=IF(@validperiod = 'NA', Null, @validperiod)
;
''')
Out[11]:
フィードバックをくれた方ありがとうございます!
Kaggleやリクルートの方ありがとうございます!
In [ ]: