{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Análise primária do projeto"},{"metadata":{},"cell_type":"markdown","source":"Neste desafio promovido pelo Kaggle, a Talking Data precisa reduzir o risco de fraude em cliques de anúncios que não geram download de aplicativos. Este cliques fraudulentos tem custo excessivo e precisam entender a jornada deste cliques.\n\nA ideia do projeto é montar um modelo de ML capaz de prever se os ips e dispositivos que geram cliques fraudulentos e assim criar uma lista negra."},{"metadata":{},"cell_type":"markdown","source":"Devido ao tamanho do dataset de treino, com mais de 8gb e tendo apenas um pc com 12gb de Ram, foram testados dois processos abaixo antes deste jupiter notebook, aqui finalizado. veja a seguir o histórico:\n\n1-) ETL completo do arquivo train.csv pelo pacote Pandas. Não foi possivel devido a limitação de memória.\n\n2-) ETL utilizando o pacote Dask (dask.org), que trabalha com particionamento de dados e possui diversas APIs do Panda, Numpy e Sklearn. Foi util no ETL e no processo de exploração dos dados, mas seria necessário reagrupar os paticionamentos para os processo de Machine Learning e durante a divisão dos dados em treino e teste. Neste ponto o pacote Dask não é pratico e em alguns casos a função não existia mais, mesmo a instrução estando disponivel na documentação oficial.\n\n3-) Por último e com sucesso foi utilizado a dica da cinetista de dados, Yulia (https://www.kaggle.com/yuliagm) que informou que uma das melhores maneiras de importar os dados, seria por uma coleta de amostra aleatória do dataset de treino. Após este processo realizado com sucesso, outro ponto fundamental foi a alteração da \"mascara\" antes da importação dos dados, afim de trazer o tamanho mínimo de cada coluna possivel.\n\nPor último fizemos a equiparação entre as variáveis alvo dentro do processo de ETL, o que reduziu mais uma vez o tamanho do dataset, sendo possivel analisar e adotar um processo de ML estável em um máquina comum.\n\nO processo de análise segue a metodologia de aprendizado supervisionado em um modelo de classificação binária."},{"metadata":{},"cell_type":"markdown","source":"### Pacotes, bibliotecas e configurações do sistema"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"#ocultando mensagens de warning\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#importanto os principais pacotes\nimport pandas as pd\nimport numpy as np\n\nimport gc\nimport os\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Extração, tratamento e limpeza de dados"},{"metadata":{},"cell_type":"markdown","source":"Neste trabalho carregaremos apenas uma amostra do dataset train.csv devido ao seu extenso tamanho e as limitações citadas acima. Porém a amostra terá 66% dos dados originais e a extração será aleatória sem reposição."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Nomeando as colunas do dataset\n#Definindo a menor \"máscara\" para a caputura dos dados, desta forma o dataset será menor que o padrão\n#de importação da função read_csv do Pandas\n\ndtypes = {\n    \n    'ip': 'uint32',\n    'app': 'uint16',\n    'device': 'uint16',\n    'os': 'uint16',\n    'channel': 'uint16',\n    'is_attributed': 'uint8',\n    \n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Usaremos 2/3 do dataset train.csv para a analise e criação do modelo de machine learning.\n\nlines = 184903891\ndivisor = 10\namostra = int(lines / divisor)\n\nskiplines = np.random.choice(np.arange(1, lines), size=lines-1-(amostra), replace=False)\nskiplines= np.sort(skiplines)\n\n#import joblib\n#with joblib.parallel_backend('dask'):\n%time train = pd.read_csv('../input/talkingdata-adtracking-fraud-detection/train.csv', skiprows=skiplines, dtype=dtypes, parse_dates=['click_time', 'attributed_time'])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Limpeza de memória, etapa necessária para a continuação do processo se você tiver uma máquina com menos\n#de 12gb de mmória Ram\ndel skiplines\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Eliminando colunas desnecessárias"},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train.drop(columns=[ 'ip', 'attributed_time'], inplace=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Analise e Balanceamento de dados"},{"metadata":{"trusted":true},"cell_type":"code","source":"target_count = train['is_attributed'].value_counts()\nprint('Click 0:', target_count[0])\nprint('Click 1:', target_count[1])\nprint('Proporção:', (round(target_count[1] / target_count[0], 6)*100), '%')\ntarget_count.plot(kind='bar', title='Distribuição de Clicks',color = ['#1F77B4', '#FF7F0E']);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Nosso modelo tem apenas uma taxa de 0,24% de clicks que geraram downloads sobre o total de clicks. Para a fase de modelagem preditiva, isso terá que ser balanceado antes da criação do modelo. Devido a grande diferença entre clicks que geraram downloads e que não geraram, vamos equalizar esse dataset antes mesmo de continuarmos para fase de análise exploratória.\n\nO método aplicado será o Undersampling, onde reduziremos a maior variável Click 0, para o mesmo patamar da variável Click 1. Em um processo com dataset menor, talvez a melhor abordagem fosse o método Oversampling, em que a menor variavel alvo é \"aumentada\", em termos de quantidade de observações, até se equiparar ao maior target do conjunto."},{"metadata":{"trusted":true},"cell_type":"code","source":"# contagem das classes 0 e 1 da variavel target\nclicks_0, clicks_1 = train['is_attributed'].value_counts()\n\n# Divisão de Classes\ndf_class_0 = train[train['is_attributed'] == 0]\ndf_class_1 = train[train['is_attributed'] == 1]\ndf_class_0_under = df_class_0.sample(clicks_1)\n\ntrain2 = pd.concat([df_class_0_under, df_class_1], axis=0)\n\nprint('Random under-sampling:')\nprint(train2['is_attributed'].value_counts())\ntrain2['is_attributed'].value_counts().plot(kind='bar', title='Distribuição de clicks',color = ['#1F77B4', '#FF7F0E']);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#limpeza de memória\n\ndel clicks_0\ndel clicks_1\ndel df_class_0\ndel df_class_1\ndel df_class_0_under\ndel train\n\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train2.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train2[\"hour\"] = train2[\"click_time\"].dt.hour\ntrain2.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Vamos deletar a coluna de data e hora \ntrain2 = train2.drop(columns=[ 'click_time'], inplace=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train2['hour'] = train2['hour'].astype('uint16')\ntrain2.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"correl = train2.corr()\nprint(correl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\n# Pairplot\nsns.pairplot(train2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Machine Learning - Escolha do modelo"},{"metadata":{"trusted":true},"cell_type":"code","source":"train2.columns","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Vamos separar as colunas em Features e Target\nfeatures = train2[\n    [\n        \n    'app', 'os', 'channel', 'hour'\n    ]\n    \n]\ntarget = train2['is_attributed'] ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Divisão do dataset em treino e teste\n\nfrom sklearn.model_selection import train_test_split\n\nX = features\ny = target\n\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=133)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# Importando os módulos necessários\n\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import KFold\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.tree import DecisionTreeClassifier\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.naive_bayes import GaussianNB\nfrom sklearn.svm import SVC\nfrom sklearn.linear_model import SGDClassifier\nfrom sklearn.ensemble import ExtraTreesClassifier\nfrom sklearn.ensemble import GradientBoostingClassifier\nfrom sklearn.ensemble import AdaBoostClassifier\nfrom sklearn.neural_network import MLPClassifier\n\n\n# Carregando features e Target\nX = features\nY = target\n\n# Definindo os valores para o número de folds\nnum_folds = 10\nseed = 7\n\n# Preparando uma lista de modelos que serão analisados.\n\n\nmodelos = []\n\n#modelos.append(('LDA', LinearDiscriminantAnalysis()))\n#modelos.append(('NB', GaussianNB()))\nmodelos.append(('KNN', KNeighborsClassifier()))\nmodelos.append(('RanF', RandomForestClassifier(bootstrap=False, max_depth=30, \n                                               max_features='log2', min_samples_split=10, \n                                               min_weight_fraction_leaf=0, n_estimators=50, warm_start=True)))\n\n#modelos.append(('SGD', SGDClassifier()))\nmodelos.append(('ExtraTree', ExtraTreesClassifier()))\nmodelos.append(('GBoost', GradientBoostingClassifier()))\n#modelos.append(('AdaBoost', AdaBoostClassifier()))\nmodelos.append(('DesTree', DecisionTreeClassifier()))\n#modelos.append(('MLP', MLPClassifier(hidden_layer_sizes=(50,50,50), activation='logistic', solver='adam', alpha=0.0001)))\n#modelos.append(('SVM', SVC()))\n\n# Avaliando cada modelo em um loop\nresultados = []\nnomes = []\n\n\n\nfor nome, modelo in modelos:\n    kfold = KFold(n_splits = num_folds, random_state = seed)\n    cv_results = cross_val_score(modelo, X, Y, cv = kfold, scoring = 'accuracy')\n    resultados.append(cv_results)\n    nomes.append(nome)\n    msg = \"%s: %f (%f)\" % (nome, cv_results.mean(), cv_results.std())\n    print(msg)\n\n\n# Boxplot para comparar os algoritmos\nfig = plt.figure()\nfig.suptitle('Comparação de Algoritmos de Classificação')\nax = fig.add_subplot(111)\nplt.boxplot(resultados)\nax.set_xticklabels(nomes)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Aplicação e Avaliação Métrica do Modelo de Machine Learning com o Random Forest"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Avaliação do modelo usando o \n\nfrom pandas import read_csv\nfrom sklearn.model_selection import KFold\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.metrics import mean_absolute_error\nfrom sklearn.metrics import r2_score\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import classification_report\n\n# Separando as features e target\nX = features\nY = target\n\n# Divide os dados em treino e teste\nX_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.33, random_state = 5)\n\n# Criando o modelo\nModel = RandomForestClassifier(bootstrap=False, max_depth=30, max_features='log2', min_samples_split=10,\n                               min_weight_fraction_leaf=0, n_estimators=50, warm_start=True)\n\n\n# Definindo os valores para o número de folds\nnum_folds = 10\nseed = 7\n    \n# Separando os dados em folds\nkfold = KFold(num_folds, True, random_state = seed)    \n    \n\n# Treinando o modelo\nModel.fit(X_train, Y_train)\n\n\n# Previsão do modelo\n\nPredict = Model.predict(X_test)\n\n\n# Acurácia final e ROC\nresultadoAC = cross_val_score(Model, X, Y, cv = kfold, scoring = 'accuracy')\nresultadoROC = cross_val_score(Model, X, Y, cv = kfold, scoring = 'roc_auc')\n\nprint(\"ROC foi de: %.3f\" % (resultadoROC.mean() * 100))\nprint(\"A Acurácia foi de: %.3f%%\" % (resultadoAC.mean() * 100.0))\n\n\nreport = classification_report(Y_test, Predict)\n\n# Imprimindo o relatório\nprint(report)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Conseguimos finalizar o modelo preditivo com uma acurácia de 91,5% aprox. Podemos considerar que este é um bom resultado e agora é so colocar em prática. Vamos salvar o modelo."},{"metadata":{},"cell_type":"markdown","source":"# FIM"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}