{"cells":[{"metadata":{"_uuid":"dc299bfe7bc6873cddd1ed0f6fa9cf4a34e509f6"},"cell_type":"markdown","source":"**一般情報**\n<br>このカーネルはElo Merchant Category Recommendationコンテス<br>トのEDAとフィーチャー・エンジニアリングに専念しています。\n<br>\n<br>このデータセットでは、Eloとそのトランザクションを使用するクラ<br>イアントを見ることができます。各card_idのロイヤリティスコアを<br>予測する必要があります。\n\n"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\n\n#可視化系\nimport seaborn as sns \nimport matplotlib.pyplot as plt\n%matplotlib inline\n#matplotlibのグラフのデザインかえれるんすねーはー知らんかった\n#https://qiita.com/eriksoon/items/b93030ba4dc686ecfbba　ここ参照\nplt.style.use('ggplot')\n\n#定番の機械学習系\nimport lightgbm as lgb\nimport xgboost as xgb\n\n#定番の時間\nimport time\nimport datetime\n\n#これもよく見るけどダミー変数作成の時に使いますね\nfrom sklearn.preprocessing import LabelEncoder\n#簡単にトレーニングデータとテストデータを分けれるやつ\nfrom sklearn.model_selection import StratifiedKFold, KFold\n#これもよく見るけど平均二乗誤差 (MSE)\n#確かこのコンペのスコア算出法は二乗平均平方根誤差 (RMSE)\n#https://pythondatascience.plavox.info/scikit-learn/%E5%9B%9E%E5%B8%B0%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E8%A9%95%E4%BE%A1\n#ここ分かり易い\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.linear_model import Ridge, RidgeCV\n#カーネル必須ガベージコレクション\nimport gc\n#catboostは珍しい様な？\nfrom catboost import CatBoostRegressor\n\n#よく見るけどmatplotlibより綺麗で3Dモデルも書けるから使ってる？？\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.tools as tls\n\n#何回かみたけどアラートっぽい　\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\npd.set_option('max_colwidth', 500)\npd.set_option('max_columns', 500)\n\n# import workalendar\n# from workalendar.america import Brazil","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"%%time\n#セルの実行時間測れます　一番上に記述しないとエラー吐くよ\n#訓練データを読み込ませる\ntrain = pd.read_csv('../input/train.csv', parse_dates=['first_active_month'])\n#テストデータを読み込ませる\ntest = pd.read_csv('../input/test.csv', parse_dates=['first_active_month'])\n#サンプル提出データを読み込ませる\nsubmission = pd.read_csv('../input/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c0fef1d6ebe74a440edf483d8f9fff2941d0ea9f"},"cell_type":"code","source":"#メモリ使用量を減らす関数を定義\ndef reduce_mem_usage(df, verbose=True):\n    #型宣言\n    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']\n    #メモリの消費割合を格納\n    start_mem = df.memory_usage().sum() / 1024**2\n    #カラム名を一つずつ引っ張ってくる\n    for col in df.columns:\n        #カラムの型をcol_typeに代入\n        col_type = df[col].dtypes\n        #型が数字だったら\n        if col_type in numerics:\n            #c_minの最低値をc_maxに最大値を入れる\n            c_min = df[col].min()\n            c_max = df[col].max()\n            #型名の最初3文字がint~型だったら\n            if str(col_type)[:3] == 'int':\n                #c_minがint8の数値範囲にあればint8型で格納する\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                #同様にint16で\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                #同様にint32\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                #同様にint64\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)  \n            else:\n                 #同様にfloat16\n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                #同様にfloat32\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    #同様にfloat64\n                    df[col] = df[col].astype(np.float64)    \n    #メモリの消費割合の算出\n    end_mem = df.memory_usage().sum() / 1024**2\n    #算出？？？？わからん\n    if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))\n    return df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"934874744d315d5418e6d93fa4ddda9f46bedd0b"},"cell_type":"markdown","source":"**メインデータの探索**\n<br>データを見てみましょう"},{"metadata":{"trusted":true,"scrolled":false,"_uuid":"ae0dd1dd05510407c3b8f98073cd31ef05f2643a"},"cell_type":"code","source":"#データディクショナリのエクセル（カラム情報かいてるとこ）\n#の訓練データ情報を開いて見てる\ne = pd.read_excel('../input/Data_Dictionary.xlsx', sheet_name='train')\ne\n\n#カラム名\n#英語名　　　　　　　　　日本語名\n#card_id　　　　　　　　カードID　　　　\n#first_active_month　　初購入月　　　　\n#feature_1            #データディクショナリのエクセル（カラム情報かいてるとこ）\n#の訓練データ情報を開いて見てる\ne = pd.read_excel('../input/Data_Dictionary.xlsx', sheet_name='train')\ne\n\n#カラム名\n#英語名　　　　　　　　　日本語名\n#card_id　　　　　　　　カードID　　　　\n#first_active_month　　初購入月　　　　\n#feature_1#データディクショナリのエクセル（カラム情報かいてるとこ）\n#の訓練データ情報を開いて見てる\ne = pd.read_excel('../input/Data_Dictionary.xlsx', sheet_name='train')\ne\n\n#カラム名\n#英語名　　　　　　　　　日本語名\n#card_id　　　　　　　　カードID　　　　\n#first_active_month　　初購入月　　　　\n#feature_1            匿名カードの分類機能(ゴールド会員？)\n#feature_2　　　　　　　３段階に分かれている\n#feature_3\n#target　　　　　　　　　履歴および評価期間の2ヶ月後に算出された\n#　　　　　　　　　　　　　ロイヤリティ数値スコア？？","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d6834d2ec79102cf37c35d25bd1416033fa27393"},"cell_type":"code","source":"#クレカ顧客のカテゴリ分けの型を'category'型に変換(文字列)\ntrain['feature_1'] = train['feature_1'].astype('category')\ntrain['feature_2'] = train['feature_2'].astype('category')\ntrain['feature_3'] = train['feature_3'].astype('category')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5dd17f7ba31065e050239fe60327838bccc462fb"},"cell_type":"code","source":"train.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"25fe6206e06b950174dd6fe7c649dcb5ed7daf4d"},"cell_type":"code","source":"#クレカ顧客のカテゴリ分け毎に\n#target　　　　　　　　　履歴および評価期間の2ヶ月後に算出された\n#　　　　　　　　　　　　　ロイヤリティ数値スコア？？\n#ターゲット(上参照)の分布度合いをヴァイオリンプロットで可視化\n#一行目は図のレイアウト設定の宣言　多分３つ横並び図を作るのにこの書き方じゃないとダメ\nfig, ax = plt.subplots(1, 3, figsize = (16, 6))\nplt.suptitle('Violineplots for features and target');\nsns.violinplot(x=\"feature_1\", y=\"target\", data=train, ax=ax[0], title='feature_1');\nsns.violinplot(x=\"feature_2\", y=\"target\", data=train, ax=ax[1], title='feature_2');\nsns.violinplot(x=\"feature_3\", y=\"target\", data=train, ax=ax[2], title='feature_3');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ce0226594c3457cc03517364d5a7717ddb951ad5"},"cell_type":"code","source":"#それぞれのカテゴリ別の顧客数\nfig, ax = plt.subplots(1, 3, figsize = (16, 6));\ntrain['feature_1'].value_counts().sort_index().plot(kind='bar', ax=ax[0], color='teal', title='feature_1');\ntrain['feature_2'].value_counts().sort_index().plot(kind='bar', ax=ax[1], color='brown', title='feature_2');\ntrain['feature_3'].value_counts().sort_index().plot(kind='bar', ax=ax[2], color='gold', title='feature_3');\nplt.suptitle('Counts of categiories for features');","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"da0d66015fae994ce0a0aa6e052a044f0166ebed"},"cell_type":"markdown","source":"これら2つのプロットは重要なアイデアを示しています。これらの機能の異なるカテゴリはさまざまな数を持つことができますが、ターゲットの分布はほぼ同じです。\nこれは、これらの機能がターゲットの予測にあまり適していないことを意味します。他の機能と機能エンジニアリングが必要になります。\nまた、これらの機能の各カテゴリの平均目標値がゼロに近いことも注目に値します。これは、データが正規分布からサンプリングされたことを意味します。"},{"metadata":{"trusted":true,"_uuid":"14811f94cacfa4d26de5878b77f3b17454aa30bb"},"cell_type":"code","source":"#テストデータの型変換も行っている\ntest['feature_1'] = test['feature_1'].astype('category')\ntest['feature_2'] = test['feature_2'].astype('category')\ntest['feature_3'] = test['feature_3'].astype('category')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2d184d21cd390bbc99520b93174dc40963613e07"},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"842b12b4e339ed121a516f7b30fb3c6667e44c1e"},"cell_type":"code","source":"#first_active_month　　初購入月\n#このカラムをsort_indexで日付（行を）昇順にソートして各々の日付の数を算出\nd1 = train['first_active_month'].value_counts().sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"30a9d3774c7fed5b86f9df6dfe9252736a92aa23"},"cell_type":"code","source":"d1.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ee80466d2f44ec823e3ba0238d374bc8e3b78ad"},"cell_type":"code","source":"#上の処理をテストデータも同様に行っている\nd2 = test['first_active_month'].value_counts().sort_index()\n#折れ線グラフの表記\n#x軸とy軸と折れ線の指定\ndata = [go.Scatter(x=d1.index, y=d1.values, name='train'), go.Scatter(x=d2.index, y=d2.values, name='test')]\n#タイトル\nlayout = go.Layout(dict(title = \"Counts of first active\",\n                  #x軸の項目名\n                  xaxis = dict(title = 'Month'),\n                  #ｙ軸の項目名\n                   yaxis = dict(title = 'Count'),\n                 #凡例orientationは配置方法だったような\n                  ),legend=dict(\n                orientation=\"v\"))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"623f77352827fe7fbffed3ebbc53fa1498cc52f1","scrolled":true},"cell_type":"code","source":"#上の処理でデータ入れて　このコードでiplot(多分plotlyがこれ)の可視化実行\npy.iplot(dict(data=data, layout=layout))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1318d3d2b4fc940402c50d12b8a656bc6cbc5229"},"cell_type":"markdown","source":"訓練データとテストデータの数の傾向は似ていて、これは素晴らしいです。\n期間の終わりになぜこんなに急激な減少があるのでしょうか。\nそれはわざとだと思います。\nあるいは、新しいカードは、いくつかの条件を満たした後にのみ考慮されます。\n\n#もしかしてコンペを考慮してるとか？\n\nまた、テストで不足しているデータを含む1行があります。私は最初のデータを記入しますが、同じ機能値を持ちます。"},{"metadata":{"trusted":true,"_uuid":"07826527320cbe80f363d04be4c549baf06d91aa"},"cell_type":"code","source":"#first_active_month　　初購入月の値が空値でfeature_1分類が5でfeature_2が2でfeature_3が１だったら\n#初購入月に最小値を入れる\ntest.loc[test['first_active_month'].isna(),'first_active_month'] = test.loc[(test['feature_1'] == 5) & (test['feature_2'] == 2) & (test['feature_3'] == 1), 'first_active_month'].min()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c1b8931faa573b5380aa2bcf5840c7da7a980da4"},"cell_type":"markdown","source":"ターゲット"},{"metadata":{"trusted":true,"_uuid":"7448b3a3f723abd75c12fc21855786c65062e34f"},"cell_type":"code","source":"#target　　　　　　　　　履歴および評価期間の2ヶ月後に算出された\n#　　　　　　　　　　　　　ロイヤリティ数値スコア？？\n#上記の分布をヒストグラム可視化\n#謎の-30\nplt.hist(train['target']);\nplt.title('Target distribution');","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"da2c9fa8675ca1fb39cb783be87155ed13f91097"},"cell_type":"markdown","source":"これは本当に奇妙に見えます！"},{"metadata":{"trusted":true,"_uuid":"40e1c15249994b6ffaa619ebc5b4b28dc07d7407"},"cell_type":"code","source":"#-20以下のターゲットの数を数えて表示\nprint('There are {0} samples with target lower than -20.'.format(train.loc[train.target < -20].shape[0]))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e5767c5533b6d40135878eb0482d7f5772d9bca2"},"cell_type":"markdown","source":"そしてそれらは1つのユニークな値を持っています：-33.21928095。\n<br>これは特別な場合のようです。これらのサンプルを単純に除外するのが妥当かもしれません。後で試します。"},{"metadata":{"_uuid":"975c935fcf55c0315d5259ecbebd61f6ecf437f4"},"cell_type":"markdown","source":"フィーチャーエンジニアリング"},{"metadata":{"trusted":true,"_uuid":"e3ebb309d1573f537a53e9f0f7a1141606d709db"},"cell_type":"code","source":"#max_date変数に　#first_active_month　　初購入月　の最終日だけを抜き出して放り込む\nmax_date = train['first_active_month'].dt.date.max()\ndef process_main(df):\n    #年、月、日に分ける？\n    date_parts = [\"year\", \"weekday\", \"month\"]\n    #１個ずつfor文回す感じ？\n    for part in date_parts:\n        #_でデータ分割\n        part_col = 'first_active_month' + \"_\" + part\n        #datetime型からint型に変換\n        df[part_col] = getattr(df['first_active_month'].dt, part).astype(int)\n    #月の最終日からどれ位前かを経過時間カラム名として追加        \n    df['elapsed_time'] = (max_date - df['first_active_month'].dt.date).dt.days\n    \n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"61e5c1f5e4b4d3e659286a1226e977588d76f058"},"cell_type":"code","source":"#わかりません\ntrain = process_main(train)\ntest = process_main(test)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"38b3c4f4b01ba131078b78d11a18f8b7d46b675d"},"cell_type":"markdown","source":"取引履歴\n<br>card_idごとに3か月分の取引履歴"},{"metadata":{"trusted":true,"_uuid":"7eac5bb3babd1d9adbda6a2cb801554db1b3e170"},"cell_type":"code","source":"#今度はData_Dictionaryのシート名がhistoryのデータを読み込む\nhistorical_transactions = pd.read_csv('../input/historical_transactions.csv')\ne = pd.read_excel('../input/Data_Dictionary.xlsx', sheet_name='history')\ne\n\n#2カードID\n#3現在から何か月前\n#4購入日\n#5決済まで終わったか　YかN\n#6カテゴリ３　A~C\n#7分割払い数\n#8カテゴリ１ YかN\n#9販売側カテゴリID\n#10 サブセクターID わかりません\n#11 販売側ID\n#12 購入数 これ意味不明\n#13 市街ID\n#14　国ID\n#15 カテゴリ２　1~4","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a3aada00f45b58d1cb92814851932d20b5b64625"},"cell_type":"code","source":"#レコード件数表示\nprint(f'{historical_transactions.shape[0]} samples in data')\nhistorical_transactions.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"44840052367ca60528862e06e0e05db3c29fd326"},"cell_type":"code","source":"#5決済まで終わったか　YかNのバイナリ値に変換しましょう\n#Yだったら1いれてNだったら0にするラムダ式いれてます。\nhistorical_transactions['authorized_flag'] = historical_transactions['authorized_flag'].apply(lambda x: 1 if x == 'Y' else 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7bb00514d15dc552a1cfb04c92fc8c7466fd2526"},"cell_type":"code","source":"#決済完了率の表示　8%位は決済失敗してる\nprint(f\"At average {historical_transactions['authorized_flag'].mean() * 100:.4f}% transactions are authorized\")\nhistorical_transactions['authorized_flag'].value_counts().plot(kind='barh', title='authorized_flag value counts');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7272accaa06c7fe311a3a1f98a165399cbc4c68c"},"cell_type":"markdown","source":"過去決済成功割合の最低ランクと最高ランク(最高は大体100%だよね)"},{"metadata":{"trusted":true,"_uuid":"76bfec94d66553bec50bd5882f5585859d11d889"},"cell_type":"code","source":"#最低ランクの方が重要で30回に1回しか成功してない　なんで？　不正取引？\nautorized_card_rate = historical_transactions.groupby(['card_id'])['authorized_flag'].mean().sort_values()\nautorized_card_rate.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9a78d06e0ba2d6cf725106441a3d9bf5bed28886"},"cell_type":"code","source":"#後ろは当然100%\nautorized_card_rate.tail()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2525ac2f55bf872dece9c688df4d51dbbf355dfe"},"cell_type":"markdown","source":"ほとんどの取引が拒否されたカードがいくつかあるようです。この不正取引はありましたか？"},{"metadata":{"_uuid":"af54b106b43afdc96b85b952f5348828f87d4e7f"},"cell_type":"markdown","source":"分割払い"},{"metadata":{"trusted":true,"_uuid":"7fa78db1809c9cd604487a4328f63bc83b3f7087"},"cell_type":"code","source":"historical_transactions['installments'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9c776e88d3543be1dbed4834f0f910d5ec1d6752"},"cell_type":"markdown","source":"面白い。最も一般的な分割払いの数は、予想される0と1です。しかし-1と999は奇妙です。これらの値は欠損値を埋めるために使用されたと思います。"},{"metadata":{"trusted":true,"_uuid":"c247f3bfdaaaa221f885d5a88b519f92dfc5138f"},"cell_type":"code","source":"#分割払いと決済完了率で集計して平均\nhistorical_transactions.groupby(['installments'])['authorized_flag'].mean()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"37f6f9163808f8518f706472a3d4552db8608d75"},"cell_type":"markdown","source":"一方、承認された取引が3％しかないことを考えると、999は不正取引を意味する可能性があるようです。もう1つ興味深いことは、分割払いの数が多いほど、承認率が低いことです。"},{"metadata":{"trusted":true,"_uuid":"2f8c155bb211d0d19ee943a0a279b63babf1231c"},"cell_type":"code","source":"#installmentsをcategory型に型変換\nhistorical_transactions['installments'] = historical_transactions['installments'].astype('category')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"07fa5839783c8c3cb4f8dd10e9437f2d3b69179b"},"cell_type":"code","source":"#purchase_date 購入日に時間も書いてあるので　日付だけに変換\nhistorical_transactions['purchase_date'] = pd.to_datetime(historical_transactions['purchase_date'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f354e3365c12000963d6435507b7a10852209c73"},"cell_type":"markdown","source":"購入金額 \n<br>残念ながら、purchase_amountは正規化されています。それにもかかわらずそれを見てみましょう。"},{"metadata":{"trusted":true,"_uuid":"5fa0c79ada08fc985afa41582adf7a0431e64d99"},"cell_type":"code","source":"plt.title('Purchase amount distribution.');\nhistorical_transactions['purchase_amount'].plot(kind='hist');","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":false,"_kg_hide-input":false,"trusted":true,"_uuid":"8ce0a00d404c401c25abf72a539695215ae8fc32"},"cell_type":"code","source":"#－１と０でループ\nfor i in [-1, 0]:\n    #purchase_amount購入量が-1と0より下の値の数を抜き出す\n    n = historical_transactions.loc[historical_transactions['purchase_amount'] < i].shape[0]\n    #プリント\n    print(f\"There are {n} transactions with purchase_amount less than {i}.\")\n#次は0,10,100\nfor i in [0, 10, 100]:\n    #今度は逆に上\n    n = historical_transactions.loc[historical_transactions['purchase_amount'] > i].shape[0]\n    print(f\"There are {n} transactions with purchase_amount more than {i}.\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"223907219dcdd82a585a8cc3c9baed2bc12b62a2"},"cell_type":"markdown","source":"-1～０がほとんどっすね"},{"metadata":{"trusted":true,"_uuid":"85db5716badcae7bc032269622aa28fc0f3aaae2"},"cell_type":"code","source":"#０以下の分布具合を可視化\nplt.title('Purchase amount distribution for negative values.');\nhistorical_transactions.loc[historical_transactions['purchase_amount'] < 0, 'purchase_amount'].plot(kind='hist');","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"68d645eb8c1cd4da4f20645c462746e64ff02bd7"},"cell_type":"markdown","source":"-0.7が多い？\n<br>ほとんどすべての取引の購入金額の範囲は（-1、0）です。かなり強い正規化と高い異常値を処理する必要があります。"},{"metadata":{"_uuid":"1012e8be95e82c8f36eda2767423b777774ecdec"},"cell_type":"markdown","source":"**カテゴリ**"},{"metadata":{"trusted":true,"_uuid":"57442d61e2e2c10adc03659c169e56abdd9f0c2c"},"cell_type":"code","source":"#置換する値を定義\nmap_dict = {'Y': 0, 'N': 1}\n#ラムダ文使ってカテゴリ１の置換実行\nhistorical_transactions['category_1'] = historical_transactions['category_1'].apply(lambda x: map_dict[x])\n#カテゴリ１を集計して　purchase_amount 購入量の平均、標準偏差、カウント数と　authorized_flag 決済完了率の平均、標準偏差を表示　これ便利だねぇ\nhistorical_transactions.groupby(['category_1']).agg({'purchase_amount': ['mean', 'std', 'count'], 'authorized_flag': ['mean', 'std']})","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a2e5b8589cf9d806206ee03cfcfcafa4597257e4"},"cell_type":"markdown","source":"上からわかることは\n<br>カテゴリ１の\n<br>Nは購入量小　バラつき小　決済完了率低　バラつき大\n<br>Yは購入量大　バラつき大　決済完了率高　バラつき小"},{"metadata":{"trusted":true,"_uuid":"5d26537aae672dfbc0c8d924048b4bec6d8421e7"},"cell_type":"markdown","source":"すべてのカテゴリはかなり異なります"},{"metadata":{"trusted":true,"_uuid":"e6047b39a9928ba58f0bb13224731e80ecd4fb98"},"cell_type":"code","source":"#ループ文でカラムまわし\nfor col in ['city_id', 'merchant_category_id', 'merchant_id', 'state_id', 'subsector_id']:\n    #各々のカラムの一意の値をカウントしてプリント\n    print(f\"There are {historical_transactions[col].nunique()} unique values in {col}.\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1ece1333b9c281054f71fcca72c334f7994294bc"},"cell_type":"markdown","source":"未だにサブセクターIDだけ謎\n\n<br>**フィーチャーエンジニアリング**"},{"metadata":{"trusted":true,"_uuid":"c8b82037f52ad352a046f7f4981771db0d89b6ad"},"cell_type":"code","source":"#取引履歴集計\ndef aggregate_historical_transactions(trans, prefix):\n    #purchase_month　購入日付の月だけ抜き出してる\n    trans['purchase_month'] = trans['purchase_date'].dt.month\n#     trans['year'] = trans['purchase_date'].dt.year\n#     trans['weekofyear'] = trans['purchase_date'].dt.weekofyear\n#     trans['month'] = trans['purchase_date'].dt.month\n#     trans['dayofweek'] = trans['purchase_date'].dt.dayofweek\n#     trans['weekend'] = (trans.purchase_date.dt.weekday >=5).astype(int)\n#     trans['hour'] = trans['purchase_date'].dt.hour\n    #何か月違うかを表記(今日の日付ー購入日付)÷30の切り捨てで計算\n    trans['month_diff'] = ((datetime.datetime.today() - trans['purchase_date']).dt.days)//30\n    #ここは意味不明だが\n    #month_lagは2018年の2月からどれだけ前の購入月か記述してるが\n    #下記のコードを実行するとおかしくならない？と思う\n    trans['month_diff'] += trans['month_lag']\n    #分割払いのカラムをint型変換\n    trans['installments'] = trans['installments'].astype(int)\n    #purchase_date 購入日付を時系列インデックスに変換するみたいだけど\n    trans.loc[:, 'purchase_date'] = pd.DatetimeIndex(trans['purchase_date']). \\\n                                        astype(np.int64) * 1e-9\n    #左の10の-9乗してる意味がさｐｐｐっぱり\n    #ダミー変数作成メソッド(男→１　女→０みたいな置換)\n    trans = pd.get_dummies(trans, columns=['category_2', 'category_3'])\n    agg_func = {\n        'authorized_flag': ['sum', 'mean'],\n        'category_1': ['sum', 'mean'],\n        'category_2_1.0': ['mean', 'sum'],\n        'category_2_2.0': ['mean', 'sum'],\n        'category_2_3.0': ['mean', 'sum'],\n        'category_2_4.0': ['mean', 'sum'],\n        'category_2_5.0': ['mean', 'sum'],\n        'category_3_1': ['sum', 'mean'],\n        'category_3_2': ['sum', 'mean'],\n        'category_3_3': ['sum', 'mean'],\n        'merchant_id': ['nunique'],\n        'purchase_amount': ['sum', 'mean', 'max', 'min', 'std'],\n        'installments': ['sum', 'mean', 'max', 'min', 'std'],\n        'purchase_month': ['mean', 'max', 'min', 'std'],\n        #ptpは値の範囲を算出してくれる\n        'purchase_date': [np.ptp, 'max', 'min'],\n        'month_lag': ['min', 'max'],\n        'merchant_category_id': ['nunique'],\n        'state_id': ['nunique'],\n        'subsector_id': ['nunique'],\n        'city_id': ['nunique'],\n        'month_diff': ['min', 'max', 'mean']\n    }\n    #aggは指定したカラム毎に集計をとってくれる\n    agg_trans = trans.groupby(['card_id']).agg(agg_func)\n    #\n    agg_trans.columns = [prefix + '_'.join(col).strip() for col in agg_trans.columns.values]\n    #インデックスの番号降りなおし\n    agg_trans.reset_index(inplace=True)\n\n    df = (trans.groupby('card_id')\n          .size()\n          .reset_index(name='{}transactions_count'.format(prefix)))\n\n    agg_trans = pd.merge(df, agg_trans, on='card_id', how='left')\n\n    return agg_trans","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"30fe1220eae9f0b9bb6d089287996f8ae5a37e2f"},"cell_type":"code","source":"#月間集計　引数history\ndef aggregate_per_month(history):\n    #カードIDと何か月前に購入したかで集計\n    grouped = history.groupby(['card_id', 'month_lag'])\n    #installments 分割払いをint型に型変換\n    history['installments'] = history['installments'].astype(int)\n    agg_func = {\n            'purchase_amount': ['count', 'sum', 'mean', 'min', 'max', 'std'],\n            'installments': ['count', 'sum', 'mean', 'min', 'max', 'std'],\n            }\n\n    intermediate_group = grouped.agg(agg_func)\n    intermediate_group.columns = ['_'.join(col).strip() for col in intermediate_group.columns.values]\n    intermediate_group.reset_index(inplace=True)\n\n    final_group = intermediate_group.groupby('card_id').agg(['mean', 'std'])\n    final_group.columns = ['_'.join(col).strip() for col in final_group.columns.values]\n    final_group.reset_index(inplace=True)\n    \n    return final_group\n\nfinal_group = aggregate_per_month(historical_transactions) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"832934efe143dfdefde48cb4294f01bb1defb070"},"cell_type":"code","source":"%%time\n#いらんデータ削除\ndel d1, d2, autorized_card_rate\n#軽くするためにガベージコレクション\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3f3301274cb02df3c6eda4dd1a755b75d57a39b4"},"cell_type":"code","source":"historical_transactions.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"40c67a3205211c3c7cd52e15cc8b42065380aa8f"},"cell_type":"code","source":"#historical_transactions 取引履歴シートに\n#メモリ使用量を減らす関数を定義\n#def reduce_mem_usage(df, verbose=True):\n#上記のメソッド放り込み\nhistorical_transactions = reduce_mem_usage(historical_transactions)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"410d2ecf1896659948515928b2464b2f45e2abfa"},"cell_type":"code","source":"historical_transactions.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"79b73a6f917f04cf463b6a38c4cd8e3ad0e3d8af"},"cell_type":"code","source":"history = aggregate_historical_transactions(historical_transactions, prefix='hist_')\nhistory = reduce_mem_usage(history)\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b8ba7ea62e45159a51d5e1bd09b4bf27ffd3ff8f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2ad666a5d9866adabcf9399d9f583bc060065ac2"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8a83a16921d9abfcf5b249e261dda26c2a9c549c"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}