{"cells":[{"metadata":{},"cell_type":"markdown","source":"### 설명\n* 80/20 규칙은 많은 기업에 적용되며 소수의 고객만이 대부분의 수익을 창출한다. 따라서 마케팅 팀은 홍보 전략에 적절한 투자를 해야한다.\n* 목표 : 고객 당 매출을 예측하기 위해 Google Merchandise Store고객데이터셋을 분석해야한다.\n* 파일설명\n    - train데이터 : 2016.08.01~2018.04.30\n    - test데이터 : 2018.05.01~2018.10.15\n    - 제출할 열은 2018.12.01~2019.01.31기간 동안에 대한 미래 예측\n\n* Data Fields\n    - fullVisitorId : Google Merchandise Store의 각 사용자에 대한 고유 식별자\n    - channelGrouping : 사용자가 스토어를 방문한 채널\n    - date : 사용자가 스토어를 방문한 날짜\n    - device : 스토어에 접근하는데 사용된 장치의 사양\n    - geoNetwork : 사용자의 지역에 대한 정보\n    - socialEngagementType : 참여유형, Socially Engaged 또는 Not Socially Engaged\n    - totals : 세션 전체의 총계 값\n    - trafficSource : 세션이 시작된 트래픽 소스에 대한 정보\n    - visitId : 세션의 식별자, 일반적으로 _utmb cookie로 저장되는 값의 일부이고 \n    사용자에게만 고유한 것, 완전히 고유한 ID의 경우 fullVisitorId와 visitId조합 사용\n    - visitNumber : 사용자의 세션 번호 (첫번째 세션인경우 1로 설정)\n    - visitStartTime : 타임 스탬프 (POSIX 시간으로 표시)\n    - hits : row and nested fields는 모든 종류의 hits에 대해 채워짐\n    - customDimensions : 이 섹션에는 세션에 대해 설정된 모든 사용자 수준 또는 세션 수준 \n    사용자 지정 차원이 포함, 이 필드는 반복되는 필드이며 설정된 각 차원에 대한 항목이 있음\n    - totals : 이 열 세트에는 주로 고급 집계 데이터가 포함"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport json\nimport numpy as np\nimport pandas as pd\nfrom pandas.io.json import json_normalize\nimport matplotlib.pyplot as plt\nimport seaborn as sns\ncolor = sns.color_palette()\n\n%matplotlib inline\n\nfrom plotly import tools\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\n\nfrom sklearn import model_selection, preprocessing, metrics\nimport lightgbm as lgb\n\npd.options.mode.chained_assignment = None\npd.options.display.max_columns = 999","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_df(csv_path='../input/ga-customer-revenue-prediction/train.csv', nrows=None):\n    JSON_COLUMNS = ['device', 'geoNetwork', 'totals', 'trafficSource']\n    \n    df = pd.read_csv(csv_path, \n                     converters={column: json.loads for column in JSON_COLUMNS}, \n                     dtype={'fullVisitorId': 'str'}, # Important!!\n                     nrows=nrows)\n    \n    for column in JSON_COLUMNS:\n        column_as_df = json_normalize(df[column])\n        column_as_df.columns = [f\"{column}.{subcolumn}\" for subcolumn in column_as_df.columns]\n        df = df.drop(column, axis=1).merge(column_as_df, right_index=True, left_index=True)\n    print(f\"Loaded {os.path.basename(csv_path)}. Shape: {df.shape}\")\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\ntrain_df = load_df()\ntest_df = load_df(\"../input/ga-customer-revenue-prediction/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Target 변수 탐색:\n\n사용자의 모든 트랜잭션의 합계를 자연 로그로 예측하고 있으므로, 사용자 수준에서 트랜잭션 수익을 집계한 후 로그를 취하여 산점도 작성"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df[\"totals.transactionRevenue\"] = train_df[\"totals.transactionRevenue\"].astype('float')\ngdf = train_df.groupby(\"fullVisitorId\")[\"totals.transactionRevenue\"].sum().reset_index()\n\nplt.figure(figsize=(8,6))\nplt.scatter(range(gdf.shape[0]), np.sort(np.log1p(gdf[\"totals.transactionRevenue\"].values)))\nplt.xlabel('index', fontsize=12)\nplt.ylabel('TransactionRevenue', fontsize=12)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"##### 80/20 규칙은 많은 기업에서 사실로 입증되었으며, 일부 고객들이 대부분의 수익을 창출하고 있다. 이처럼 마케팅팀은 홍보 전략에 적절한 투자를 해야 하는 과제를 안고 있다."},{"metadata":{"trusted":true},"cell_type":"code","source":"nzi = pd.notnull(train_df[\"totals.transactionRevenue\"]).sum()\nnzr = (gdf[\"totals.transactionRevenue\"]>0).sum()\nprint(\"수익 0이 아닌 train 세트의 경우의 수 : \", nzi, \" 비율 : \", nzi / train_df.shape[0])\nprint(\"매출 0이 아닌 고유한 고객 수 : \", nzr, \" 비율 : \", nzr / gdf.shape[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"##### 따라서 수익이 발생하는 고객들의 비율은 수익이 발생하지 않는 고객들의 1.3%비율\n\n#### 방문자 및 일반 방문자 수:\n\n이제 train와 test에 있는 고유한 방문객들의 수와 일반 방문객의 수를 살펴보자"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"train set의 고유 방문자 수 : \",train_df.fullVisitorId.nunique(), \" out of rows : \",train_df.shape[0])\nprint(\"test set의 고유 방문자 수 : \",test_df.fullVisitorId.nunique(), \" out of rows : \",test_df.shape[0])\nprint(\"train 및 test set의 일반 방문자수 : \",len(set(train_df.fullVisitorId.unique()).intersection(set(test_df.fullVisitorId.unique())) ))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### 일정한 값이 있는 열\n\ntrain set에는 일정한 값을 가진 특징들이 꽤 많이 있다. 이 특징들의 list를 보면 일정한 값과 일부 null 값을 갖는 열을 포함하면 안된다."},{"metadata":{"trusted":true},"cell_type":"code","source":"const_cols = [c for c in train_df.columns if train_df[c].nunique(dropna=False)==1 ]\nconst_cols","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"##### 꽤 많은데 값이 일정하기 때문에 feature 목록에서 삭제하고 모델링 프로세스에서 메모리와 시간을 절약할 수 있다."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Device Information:\ndef horizontal_bar_chart(cnt_srs, color):\n    trace = go.Bar(\n        y=cnt_srs.index[::-1],\n        x=cnt_srs.values[::-1],\n        showlegend=False,\n        orientation = 'h',\n        marker=dict(\n            color=color,\n        ),\n    )\n    return trace\n\n# Device Browser\ncnt_srs = train_df.groupby('device.browser')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'rgba(50, 171, 96, 0.6)')\ntrace2 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10), 'rgba(50, 171, 96, 0.6)')\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), 'rgba(50, 171, 96, 0.6)')\n\n# Device Category\ncnt_srs = train_df.groupby('device.deviceCategory')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'rgba(71, 58, 131, 0.8)')\ntrace5 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10), 'rgba(71, 58, 131, 0.8)')\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), 'rgba(71, 58, 131, 0.8)')\n\n# Operating system\ncnt_srs = train_df.groupby('device.operatingSystem')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace7 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'rgba(246, 78, 139, 0.6)')\ntrace8 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10),'rgba(246, 78, 139, 0.6)')\ntrace9 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10),'rgba(246, 78, 139, 0.6)')\n\n# Creating two subplots\nfig = tools.make_subplots(rows=3, cols=3, vertical_spacing=0.04, \n                          subplot_titles=[\"Device Browser - Count\", \"Device Browser - Non-zero Revenue Count\", \"Device Browser - Mean Revenue\",\n                                          \"Device Category - Count\",  \"Device Category - Non-zero Revenue Count\", \"Device Category - Mean Revenue\", \n                                          \"Device OS - Count\", \"Device OS - Non-zero Revenue Count\", \"Device OS - Mean Revenue\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\nfig.append_trace(trace7, 3, 1)\nfig.append_trace(trace8, 3, 2)\nfig.append_trace(trace9, 3, 3)\n\nfig['layout'].update(height=1200, width=1200, paper_bgcolor='rgb(233,233,233)', title=\"Device Plots\")\npy.iplot(fig, filename='device-plots')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- 장치 브라우저 배포가 0이 아닌 수익 plot의 갯수와 갯수 모두에서 유사하게 표시됨\n- device 카테고리 전면에서 데스크톱은 모바일 기기에 비해 0이 아닌 매출의 비율이 더 높은 것으로 보임\n- 장치 운영 체제에서는 윈도우에서 카운트 수가 더 많지만, 수익이 0이 아닌 카운트 수는 Macintosh에서 더 많다.\n- 또한 Chrome OS는 0이 아닌 수익의 비율도 더 높다.\n- 모바일 OS 측면에서는 iOS가 안드로이드에 비해 0이 아닌 매출의 비율이 더 높다."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Date Exploration:\n\nimport datetime\n\ndef scatter_plot(cnt_srs, color):\n    trace = go.Scatter(\n        x=cnt_srs.index[::-1],\n        y=cnt_srs.values[::-1],\n        showlegend=False,\n        marker=dict(\n            color=color,\n        ),\n    )\n    return trace\n\ntrain_df['date'] = train_df['date'].apply(lambda x: datetime.date(int(str(x)[:4]), int(str(x)[4:6]), int(str(x)[6:])))\ncnt_srs = train_df.groupby('date')['totals.transactionRevenue'].agg(['size', 'count'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\"]\ncnt_srs = cnt_srs.sort_index()\n#cnt_srs.index = cnt_srs.index.astype('str')\ntrace1 = scatter_plot(cnt_srs[\"count\"], 'red')\ntrace2 = scatter_plot(cnt_srs[\"count of non-zero revenue\"], 'blue')\n\nfig = tools.make_subplots(rows=2, cols=1, vertical_spacing=0.08,\n                          subplot_titles=[\"Date - Count\", \"Date - Non-zero Revenue count\"])\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 2, 1)\nfig['layout'].update(height=800, width=800, paper_bgcolor='rgb(233,233,233)', title=\"Date Plots\")\npy.iplot(fig, filename='date-plots')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"train 데이터 세트에 2016년 8월 1일부터 2017년 7월 31일까지 데이터가 있음\n2016년 11월, 방문자 수는 증가하지만, 그 기간(평균 대비)에는 0이 아닌 매출 수가 증가하지 않는다."},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df['date'] = test_df['date'].apply(lambda x: datetime.date(int(str(x)[:4]), int(str(x)[4:6]), int(str(x)[6:])))\ncnt_srs = test_df.groupby('date')['fullVisitorId'].size()\n\n\ntrace = scatter_plot(cnt_srs, 'red')\n\nlayout = go.Layout(\n    height=400,\n    width=800,\n    paper_bgcolor='rgb(233,233,233)',\n    title='Dates in Test set'\n)\n\ndata = [trace]\nfig = go.Figure(data=data, layout=layout)\npy.iplot(fig, filename=\"ActivationDate\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"test 세트에는 2017년 8월 2일부터 2018년 4월 30일까지 날짜가 있다. 그래서 train과 test세트 사이에는 겹치는 날짜가 없다. 따라서 이 데이터 집합에 대해 시간 기반 검증을 수행하는 것이 좋을 수 있다."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Geographic Information:\n# Continent\ncnt_srs = train_df.groupby('geoNetwork.continent')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'rgba(58, 71, 80, 0.6)')\ntrace2 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10), 'rgba(58, 71, 80, 0.6)')\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), 'rgba(58, 71, 80, 0.6)')\n\n# Sub-continent\ncnt_srs = train_df.groupby('geoNetwork.subContinent')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"], 'orange')\ntrace5 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"], 'orange')\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"], 'orange')\n\n# Network domain\ncnt_srs = train_df.groupby('geoNetwork.networkDomain')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace7 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'blue')\ntrace8 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10), 'blue')\ntrace9 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), 'blue')\n\n# Creating two subplots\nfig = tools.make_subplots(rows=3, cols=3, vertical_spacing=0.08, horizontal_spacing=0.15, \n                          subplot_titles=[\"Continent - Count\", \"Continent - Non-zero Revenue Count\", \"Continent - Mean Revenue\",\n                                          \"Sub Continent - Count\",  \"Sub Continent - Non-zero Revenue Count\", \"Sub Continent - Mean Revenue\",\n                                          \"Network Domain - Count\", \"Network Domain - Non-zero Revenue Count\", \"Network Domain - Mean Revenue\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\nfig.append_trace(trace7, 3, 1)\nfig.append_trace(trace8, 3, 2)\nfig.append_trace(trace9, 3, 3)\n\nfig['layout'].update(height=1500, width=1200, paper_bgcolor='rgb(233,233,233)', title=\"Geography Plots\")\npy.iplot(fig, filename='geo-plots')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"continent plot에서, 우리는 미국이 더 많은 수의 카운트와 0이 아닌 가장 높은 카운트 수를 가지고 있다는 것을 알 수 있다.\n아시아와 유럽은 높은 카운트 수를 가지고 있지만, 이들 대륙의 0이 아닌 수입의 수는 상대적으로 낮다.\n우리는 또한 아시아 대륙 그림에서 처음 두 점을 유추할 수 있다.\n네트워크 도메인이 \"(not set)\"이 아닌 \"unknown.unknown\"인 경우, 0이 아닌 수익을 갖는 카운트 수는 더 낮은 경향이 있다."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Traffic Source:\n# Continent\ncnt_srs = train_df.groupby('trafficSource.source')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), 'green')\ntrace2 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(10), 'green')\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), 'green')\n\n# Sub-continent\ncnt_srs = train_df.groupby('trafficSource.medium')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"], 'purple')\ntrace5 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"], 'purple')\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"], 'purple')\n\n# Creating two subplots\nfig = tools.make_subplots(rows=2, cols=3, vertical_spacing=0.08, horizontal_spacing=0.15, \n                          subplot_titles=[\"Traffic Source - Count\", \"Traffic Source - Non-zero Revenue Count\", \"Traffic Source - Mean Revenue\",\n                                          \"Traffic Source Medium - Count\",  \"Traffic Source Medium - Non-zero Revenue Count\", \"Traffic Source Medium - Mean Revenue\"\n                                          ])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\n\nfig['layout'].update(height=1000, width=1200, paper_bgcolor='rgb(233,233,233)', title=\"Traffic Source Plots\")\npy.iplot(fig, filename='traffic-source-plots')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"트래픽 소스 plot에서, 유튜브는 데이터 집합의 카운트 수가 높지만, 0이 아닌 수익 카운트의 수는 매우 적다.\n구글플렉스는 트래픽 소스 플롯의 총계수 대비 0이 아닌 수익수 비율이 높다.\n트래픽 소스 매체의 경우, \"referral\"은 \"organic\" 매체에 비해 0이 아닌 매출의 수가 더 많다.","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### 방문자 프로파일:\n\n방문자의 페이지뷰 수, 방문자의 히트 수 등과 같은 방문자 프로필 변수를 보고 어떻게 보이는지 보자"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Page views\ncnt_srs = train_df.groupby('totals.pageviews')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(60), 'cyan')\ntrace2 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(60), 'cyan')\ntrace5 = horizontal_bar_chart(cnt_srs[\"mean\"].head(60), 'cyan')\n\n# Hits\ncnt_srs = train_df.groupby('totals.hits')['totals.transactionRevenue'].agg(['size', 'count', 'mean'])\ncnt_srs.columns = [\"count\", \"count of non-zero revenue\", 'mean']\ncnt_srs = cnt_srs.sort_values(by=\"count\", ascending=False)\ntrace3 = horizontal_bar_chart(cnt_srs[\"count\"].head(60), 'black')\ntrace4 = horizontal_bar_chart(cnt_srs[\"count of non-zero revenue\"].head(60), 'black')\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"].head(60), 'black')\n\n# Creating two subplots\nfig = tools.make_subplots(rows=2, cols=3, vertical_spacing=0.08, horizontal_spacing=0.15, \n                          subplot_titles=[\"Total Pageviews - Count\", \"Total Pageviews - Non-zero Revenue Count\", \"Total Pageviews - Mean Revenue\",\n                                          \"Total Hits - Count\",  \"Total Hits - Non-zero Revenue Count\", \"Total Hits - Mean Revenue\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace5, 1, 3)\nfig.append_trace(trace3, 2, 1)\nfig.append_trace(trace4, 2, 2)\nfig.append_trace(trace6, 2, 3)\n\nfig['layout'].update(height=1200, width=900, paper_bgcolor='rgb(233,233,233)', title=\"Visitor Profile Plots\")\npy.iplot(fig, filename='visitor-profile-plots')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- 이 두 변수 모두 예측성이 매우 높아 보인다.\n- count plot은 자연 감소를 보여준다. 즉, 방문자 트랜잭션당 조회 수와 페이지 뷰 수를 줄이기 위해 총 카운트가 매우 높으며 방문자 트랜잭션당 조회 수가 증가하면 전체 카운트가 감소한다.\n- 반면, 방문자 거래당 조회수/페이지뷰수가 증가하면, 0이 아닌 매출수가 많다는 것을 명확히 알 수 있다."},{"metadata":{},"cell_type":"markdown","source":"Baseline Model:\n\n이 데이터 집합에 기본 모델을 구축해 본다. 모델을 구축하기 전에, test 데이터 set이 아닌 train 데이터 set에 있는 변수 이름을 살펴보자"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"test가 아닌 train 내에 있는 변수 : \", set(train_df.columns).difference(set(test_df.columns)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"따라서 대상 변수와는 별도로 test 데이터 set에 없는 \"trafficSource.campaignCode\" 변수가 하나 더 있다. 그래서 우리는 모델을 만들면서 이 변수를 제거해야 한다. 또한 우리는 우리가 이전에 얻었던 지속적인 변수들을 버릴 수 있다.\n\n또한 \"sessionId\"는 방문의 고유 식별자이기 때문에 제거할 수 있다."},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_to_drop = const_cols + ['sessionId']\n\ntrain_df = train_df.drop(cols_to_drop + [\"trafficSource.campaignCode\"], axis=1)\ntest_df = test_df.drop(cols_to_drop, axis=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"모델을 구축하기 위한 시간을 기준으로 개발 및 검증 분할을 생성"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Impute 0 for missing target values\ntrain_df[\"totals.transactionRevenue\"].fillna(0, inplace=True)\ntrain_y = train_df[\"totals.transactionRevenue\"].values\ntrain_id = train_df[\"fullVisitorId\"].values\ntest_id = test_df[\"fullVisitorId\"].values\n\n\n# label encode the categorical variables and convert the numerical variables to float\ncat_cols = [\"channelGrouping\", \"device.browser\", \n            \"device.deviceCategory\", \"device.operatingSystem\", \n            \"geoNetwork.city\", \"geoNetwork.continent\", \n            \"geoNetwork.country\", \"geoNetwork.metro\",\n            \"geoNetwork.networkDomain\", \"geoNetwork.region\", \n            \"geoNetwork.subContinent\", \"trafficSource.adContent\", \n            \"trafficSource.adwordsClickInfo.adNetworkType\", \n            \"trafficSource.adwordsClickInfo.gclId\", \n            \"trafficSource.adwordsClickInfo.page\", \n            \"trafficSource.adwordsClickInfo.slot\", \"trafficSource.campaign\",\n            \"trafficSource.keyword\", \"trafficSource.medium\", \n            \"trafficSource.referralPath\", \"trafficSource.source\",\n            'trafficSource.adwordsClickInfo.isVideoAd', 'trafficSource.isTrueDirect']\nfor col in cat_cols:\n    print(col)\n    lbl = preprocessing.LabelEncoder()\n    lbl.fit(list(train_df[col].values.astype('str')) + list(test_df[col].values.astype('str')))\n    train_df[col] = lbl.transform(list(train_df[col].values.astype('str')))\n    test_df[col] = lbl.transform(list(test_df[col].values.astype('str')))\n\n\nnum_cols = [\"totals.hits\", \"totals.pageviews\", \"visitNumber\", \"visitStartTime\", 'totals.bounces',  'totals.newVisits']    \nfor col in num_cols:\n    train_df[col] = train_df[col].astype(float)\n    test_df[col] = test_df[col].astype(float)\n\n# Split the train dataset into development and valid based on time \ndev_df = train_df[train_df['date']<=datetime.date(2017,5,31)]\nval_df = train_df[train_df['date']>datetime.date(2017,5,31)]\ndev_y = np.log1p(dev_df[\"totals.transactionRevenue\"].values)\nval_y = np.log1p(val_df[\"totals.transactionRevenue\"].values)\n\ndev_X = dev_df[cat_cols + num_cols] \nval_X = val_df[cat_cols + num_cols] \ntest_X = test_df[cat_cols + num_cols] ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# custom function to run light gbm model\ndef run_lgb(train_X, train_y, val_X, val_y, test_X):\n    params = {\n        \"objective\" : \"regression\",\n        \"metric\" : \"rmse\", \n        \"num_leaves\" : 30,\n        \"min_child_samples\" : 100,\n        \"learning_rate\" : 0.1,\n        \"bagging_fraction\" : 0.7,\n        \"feature_fraction\" : 0.5,\n        \"bagging_frequency\" : 5,\n        \"bagging_seed\" : 2018,\n        \"verbosity\" : -1\n    }\n    \n    lgtrain = lgb.Dataset(train_X, label=train_y)\n    lgval = lgb.Dataset(val_X, label=val_y)\n    model = lgb.train(params, lgtrain, 1000, valid_sets=[lgval], early_stopping_rounds=100, verbose_eval=100)\n    \n    pred_test_y = model.predict(test_X, num_iteration=model.best_iteration)\n    pred_val_y = model.predict(val_X, num_iteration=model.best_iteration)\n    return pred_test_y, model, pred_val_y\n\n# Training the model #\npred_test, model, pred_val = run_lgb(dev_X, dev_y, val_X, val_y, test_X)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"이제 이 새로운 토론 스레드에서 언급한 검증 데이터에 대한 평가 메트릭을 계산해 보자. 그래서 우리는 사용자의 모든 거래에 대해 합계를 내고 그 위에 로그 변환을 해야 한다. 또한 거래 수익은 0 이상일 수 있으므로 값을 0에서 0 미만으로 설정한다."},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn import metrics\npred_val[pred_val<0] = 0\nval_pred_df = pd.DataFrame({\"fullVisitorId\":val_df[\"fullVisitorId\"].values})\nval_pred_df[\"transactionRevenue\"] = val_df[\"totals.transactionRevenue\"].values\nval_pred_df[\"PredictedRevenue\"] = np.expm1(pred_val)\n#print(np.sqrt(metrics.mean_squared_error(np.log1p(val_pred_df[\"transactionRevenue\"].values), np.log1p(val_pred_df[\"PredictedRevenue\"].values))))\nval_pred_df = val_pred_df.groupby(\"fullVisitorId\")[\"transactionRevenue\", \"PredictedRevenue\"].sum().reset_index()\nprint(np.sqrt(metrics.mean_squared_error(np.log1p(val_pred_df[\"transactionRevenue\"].values), np.log1p(val_pred_df[\"PredictedRevenue\"].values))))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So we are getting a validation score of 1.70 using this method against the public leaderboard score of 1.44. So please be cautious while dealing with this.\n\nNow let us prepare the submission file similar to validation set."},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = pd.DataFrame({\"fullVisitorId\":test_id})\npred_test[pred_test<0] = 0\nsub_df[\"PredictedLogRevenue\"] = np.expm1(pred_test)\nsub_df = sub_df.groupby(\"fullVisitorId\")[\"PredictedLogRevenue\"].sum().reset_index()\nsub_df.columns = [\"fullVisitorId\", \"PredictedLogRevenue\"]\nsub_df[\"PredictedLogRevenue\"] = np.log1p(sub_df[\"PredictedLogRevenue\"])\nsub_df.to_csv(\"baseline_lgb.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Feature Importance"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(figsize=(12,18))\nlgb.plot_importance(model, max_num_features=50, height=0.8, ax=ax)\nax.grid(False)\nplt.title(\"LightGBM - Feature Importance\", fontsize=15)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\"totals.pageviews\"가 \"totals.hits\"와 \"visitStartTime\"에 이어 가장 중요한 기능으로 나타남"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}