Advertisement
Guest User

Untitled

a guest
Dec 17th, 2017
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.88 KB | None | 0 0
  1. ---
  2. title: "Análise de dados com R"
  3. subtitle: "Estudo de Caso: Czech Bank"
  4. date: "17 de Dezembro de 2017"
  5. author:
  6. - name: "André Ferreira Bem"
  7. - name: "Augusto Gonçalves"
  8. - name: "Fernando D'Imperio"
  9. - name: "Marcos Vinício de Siqueira"
  10. affiliation: "Fundação Getulio Vargas - FGV"
  11. output:
  12. html_document: default
  13. ---
  14.  
  15. ```{r setup, include=FALSE}
  16. knitr::opts_chunk$set(echo = TRUE, fig.align='center',fig.height=5,fig.width=6)
  17.  
  18. #Instalar os seguintes pacotes:
  19. package.requirements <- c("ggplot2", "dplyr", "kableExtra", "knitr", "corrplot", "readxl", "GGally")
  20. #install.packages(package.requirements)
  21.  
  22. # Loads all libraries
  23. lapply(package.requirements, library, character.only = TRUE)
  24.  
  25. ```
  26. ---
  27.  
  28. ### 1. ESTUDO DE CASO
  29.  
  30. Este trabalho visa auxiliar os gerentes de um banco Czech a entender melhor seus clientes para que os mesmos tenham condições de oferecer melhores serviços aos seus melhores clientes.
  31.  
  32. Para esta análise, foi disponibilizado a base de dados do Czech Bank contendo informações de Jan/1993 a Dez/1998.
  33.  
  34. Estes base contém as seguintes tabelas:
  35.  
  36.  
  37. ```{r echo=FALSE, message=FALSE}
  38.  
  39. TABELAS <- c ("Client (Clientes)",
  40. "Account (Contas)",
  41. "Disposition (Vínculos Clientes x Contas)",
  42. "Demograph (Informações Geográficas)",
  43. "Credit Card (Cartões de Crédito)",
  44. "Loan (Empréstimos)",
  45. "Permanent order (Ordens Permanentes)",
  46. "Transactions (Transações)")
  47.  
  48. kable(
  49. TABELAS,
  50. format = "html",
  51. align="l",
  52. caption = "Tabela 1 - Base de dados"
  53. ) %>%
  54. kable_styling(
  55. bootstrap_options = c("striped","hover","condensed"),
  56. font_size = 10
  57. )
  58.  
  59.  
  60. ```
  61. ---
  62.  
  63. ### 2. METODOLOGIA
  64.  
  65. Para efetuar as análises primeiro os dados foram imporatados para o R e foram normalizados.
  66.  
  67. Então, criamos um StarSchema com a finalidade de criar uma única tabela com a granulidade sendo os clientes:
  68.  
  69. ```{r echo=FALSE, message=FALSE}
  70.  
  71. TABELAS <- c("client_id", "gender", "age", "account_id", "card" ,"year_card",
  72. "acnt_frequency", "year_account", "loan_status", "year_loan", "duration_loan", "mth_to_pay_loan")
  73.  
  74. kable(
  75. TABELAS,
  76. format = "html",
  77. align="l",
  78. caption = "Tabela 2 - Tabela de análise"
  79. ) %>%
  80. kable_styling(
  81. bootstrap_options = c("striped","hover","condensed"),
  82. font_size = 10
  83. )
  84.  
  85. ```
  86. ---
  87.  
  88. ### 3. NORMALIZAÇÃO DA BASE DE DADOS
  89.  
  90. Como visto na seção 1, há 8 tabelas que faz parte do star schema de interesse da análise de dados. As diversas tabelas possuem strings em tchecho e portanto, fez-se necessário traduzir diversas colunas. Para fins de programação e internacionalização preferiu-se traduzir os termos para o inglês. Segue uma lista dos termos em tcheco e suas mesmas versões em inglês:
  91.  
  92. ```{r echo=TRUE, message=FALSE}
  93. GetFrequencyValuesEn <- function()
  94. {
  95. return (list(MONTHLY = "Monthly", WEEKLY = "Weekly", TRANSACTION = "AfterTransaction"))
  96. }
  97.  
  98.  
  99. GetFrequencyValuesCz <- function()
  100. {
  101. return (list(MONTHLY = "POPLATEK MESICNE", WEEKLY = "POPLATEK TYDNE", TRANSACTION = "POPLATEK PO OBRATU"))
  102. }
  103.  
  104. GetTypeValuesCz <- function()
  105. {
  106. return (list(CREDIT = "PRIJEM", DEBIT = "VYDAJ", CHOICE = "VYBER"))
  107. }
  108.  
  109. GetTypeValuesEn <- function()
  110. {
  111. # Debit is called withdrawal on the pdf but debit is a more common name
  112. return (list(CREDIT = "Credit", DEBIT = "Debit", CHOICE = "Choice"))
  113. }
  114.  
  115. GetOperationValuesCz <- function()
  116. {
  117. return (list(CARDDEBIT = "VYBER KARTOU", CASHCREDIT = "VKLAD", CASHDEBIT = "VYBER",
  118. OTHERBANKCREDIT = "PREVOD Z UCTU", OTHERBANKDEBIT = "PREVOD NA UCET"))
  119. }
  120.  
  121. GetOperationValuesEn <- function()
  122. {
  123. # remittance to another bank = sum of money sent to other institution
  124. # collection = credit from another institution
  125. return (list(CARDDEBIT = "CardDebit", CASHCREDIT = "CashCredit", CASHDEBIT = "CashDebit",
  126. OTHERBANKCREDIT = "OtherBankCredit", OTHERBANKDEBIT = "OtherBankDebit"))
  127. }
  128.  
  129. GetLoanStatusEn <- function()
  130. {
  131. return (list(FINISHEDOK = "ContractFinishedOk", FINISHEDDEFAULT = "ContractFinishedDefault", RUNNINGOK = "RunningOk", RUNNINGDEBT = "RunningInDebt"))
  132. }
  133.  
  134. GetLoanStatusLetters <- function()
  135. {
  136. return (list(FINISHEDOK = "A", FINISHEDDEFAULT = "B", RUNNINGOK = "C", RUNNINGDEBT = "D"))
  137. }
  138.  
  139. # k_symbol is a column in permanent order and also in transactions
  140. GetKsymbolValuesEn <- function()
  141. {
  142. return (list(INSURANCE = "Insurance", HOUSEHOLD = "Household", LEASING = "Leasing", LOAN = "Loan", PENSION = "Pension", STATEMENT = "StatementForPayment", SANCTION = "SanctionNegativeBalance", INTEREST = "InterestCredit"))
  143. }
  144.  
  145. GetKsymbolValuesCz <- function()
  146. {
  147. return (list(INSURANCE = "POJISTNE", HOUSEHOLD = "SIPO", LEASING = "LEASING", LOAN = "UVER", PENSION = "DUCHOD", STATEMENT = "SLUZBY", SANCTION = "SANKC. UROK", INTEREST = "UROK"))
  148. }
  149. ```
  150.  
  151. Para mapear os valores fez-se o mapeamento das traduções diretamente nas bases lidas. Por exemplo:
  152.  
  153. ```{r echo=TRUE, message=FALSE}
  154. ReadPermanentOrdersDataFrame <- function()
  155. {
  156. orders.df <- (ReadDataFrameFromFilepath("order.asc"))
  157.  
  158. ks.cz <- GetKsymbolValuesCz()
  159. ks.en <- GetKsymbolValuesEn()
  160.  
  161. orders.df$k_symbol <- mapvalues(orders.df$k_symbol,
  162. from = c(ks.cz$INSURANCE, ks.cz$HOUSEHOLD, ks.cz$LEASING, ks.cz$LOAN),
  163. to = c(ks.en$INSURANCE, ks.en$HOUSEHOLD, ks.en$LEASING, ks.en$LOAN))
  164.  
  165. return (as.data.frame(orders.df))
  166. }
  167. ```
  168.  
  169. A função mapvalues mapeia os valores na coluna k_symbol, nesse caso, traduzindo do nome tcheco para o nome em inglês.
  170.  
  171. Uma outra função utilizada na normalização foi a de normalização das datas numéricas:
  172.  
  173. ```{r echo=TRUE, message=FALSE}
  174. GetDateFromBirthNumber <- function(birthnumber)
  175. {
  176. return (stri_extract_all(birthnumber, regex="\\d{2}")[[1]])
  177. }
  178.  
  179. GetBirthDateYyMmDd <- function(birthnumber)
  180. {
  181. yymmdd <- GetDateFromBirthNumber(birthnumber)
  182.  
  183. yy <- yymmdd[1]
  184. mm <- yymmdd[2]
  185. dd <- yymmdd[3]
  186.  
  187. return (sprintf('19%s/%s/%s', yy, mm, dd))
  188. }
  189. ```
  190.  
  191. Apesar disso, para as datas da tabela Cliente:
  192.  
  193. ```{r echo=TRUE, message=FALSE}
  194. # birthnumber is in the format YYMMDD - if it is a woman it is DD + 50
  195. GenderFromDate <- function(birthnumber)
  196. {
  197. yymmdd <- GetDateFromBirthNumber(birthnumber)
  198.  
  199. yy <- as.integer(yymmdd[1])
  200. mm <- as.integer(yymmdd[2])
  201. dd <- as.integer(yymmdd[3])
  202.  
  203. return (ifelse(mm < 50, 0 , 1))
  204. }
  205.  
  206. GetBirthDateYyMmDd <- function(birthnumber)
  207. {
  208. yymmdd <- GetDateFromBirthNumber(birthnumber)
  209.  
  210. yy <- as.integer(yymmdd[1])
  211. mm <- as.integer(yymmdd[2])
  212. mm <- ifelse(mm < 50, mm, mm - 50)
  213. dd <- as.integer(yymmdd[3])
  214.  
  215. return (sprintf('19%s/%s/%s', yy, mm, dd))
  216. }
  217. ```
  218.  
  219. Uma vez que o dado de gênero é codificado junto com o mês.
  220.  
  221. Finalmente, os dados de distrito estão todos codificados com acrônimos e pseudocódigos, sendo assim, troca-se explicitamente suas colunas por valores mais legíveis:
  222.  
  223. ```{r echo=TRUE, message=FALSE}
  224. ReadDistrictsDataFrame <- function()
  225. {
  226. districts.df <- ReadDataFrameFromFilepath("district.asc")
  227.  
  228. #Normalizes columns names of districts.df
  229. colnames(districts.df) <- c("district_id","district_name","region","n_inhabitants","municip_less_499","municip_between_500_1999","municip_between_2000_9999","municip_more_10000", "n_cities","ratio_urban_inhab","avg_salary","unemploy_rate_95","unemploy_rate_96","n_entrepreneurs_1000_inhab","n_commited_crimes_95","n_commited_crimes_96")
  230.  
  231. return (districts.df)
  232. }
  233. ```
  234.  
  235. ---
  236.  
  237. ### 4. SCORE DOS CLIENTES
  238.  
  239. Para atribuição de notas dos clientes utilizou-se os valores contídos nas variáveis que possuem o maior peso para tal classificação. Para varíaveis do tipo char, foi utilizada a seguinte função:
  240.  
  241. ```{r echo=TRUE, message=FALSE}
  242. GetScoreForFactorVariables <- function(data, discript, strings)
  243. {
  244. values <- data[, discript]
  245. scores <- 1:length(strings)
  246. names(scores) <- strings
  247. data$scores <- scores[values]
  248.  
  249. return (data$scores)
  250. }
  251. ```
  252.  
  253. E para variáveis do tipo numéricas, foi utilizada a seguinte função:
  254.  
  255. ```{r echo=TRUE, message=FALSE}
  256. GetScoreForNumericVariables <- function(data, posneg)
  257. {
  258. values <- as.double(unlist(data))
  259. score <- as.integer(NA)
  260. data <- data.frame(values, score)
  261.  
  262. posneg = "p"
  263. range1 <- between(data$values,quantile(data$values, na.rm = T)[1],quantile(data$values, na.rm = T)[2])
  264. range2 <- between(data$values,quantile(data$values, na.rm = T)[2],quantile(data$values, na.rm = T)[3])
  265. range3 <- between(data$values,quantile(data$values, na.rm = T)[3],quantile(data$values, na.rm = T)[4])
  266. range4 <- between(data$values,quantile(data$values, na.rm = T)[4],quantile(data$values, na.rm = T)[5])
  267.  
  268. if(posneg == "p")
  269. {
  270. data$score <- ifelse(range1 == TRUE, 1,ifelse(range2 == TRUE, 2,ifelse(range3 == TRUE, 3, ifelse(range4 == TRUE, 4, NA))))
  271.  
  272. return(data$score)
  273.  
  274. }else if(posneg == "n")
  275. {
  276. data$score <- ifelse(range1 == TRUE, 4,ifelse(range2 == TRUE, 3,ifelse(range3 == TRUE, 2, ifelse(range4 == TRUE, 1, NA))))
  277.  
  278. return(data$score)
  279. }else
  280. {
  281. print("Insira p ou n para obter o score desejado.")
  282. }
  283. }
  284. ```
  285.  
  286. Ambas funções calculam a nota do escore de acordo com os valores das variáveis. Essa nota será utilizada para a elaboração de um data frame que terá as variáveis utilizadas para a análise e a soma da nota final de cada cliente.
  287.  
  288. Através desse escore conseguiremos saber quem é um bom cliente e quem é um mal cliente. Este data frame foi gerado conforme o código que segue:
  289.  
  290. ```{r echo=TRUE, message=FALSE}
  291. ConvertCharAndIntegerVariables <- function(data){
  292. data[sapply(data, is.integer)] <- lapply(data[sapply(data, is.integer)], as.numeric)
  293. data[sapply(data, is.character)] <- lapply(data[sapply(data, is.character)], as.factor)
  294.  
  295. return(sapply(data, class))
  296. }
  297.  
  298. # joins
  299. joinclientdistrict <- inner_join(clientsdisp.df, districts.df, by = c("district_id","district_id"))
  300. joinaccountdistrict <- inner_join(accounts.df, districts.df, by = c("district_id","district_id"))
  301. joinclientaccount <- inner_join(clientsdisp.df, accounts.df, by = c("account_id","account_id"))
  302. joinclientcard <- left_join(joinclientdistrict, cards.df, by = c("disp_id","disp_id"))
  303. joinclientacntloans <- left_join(joinclientaccount, loans.df,by = c("account_id","account_id"))
  304.  
  305.  
  306. # renaming columns
  307. colnames(joinclientdistrict)[3] <- c("cl_district_id")
  308. colnames(joinclientdistrict)[9] <- c("type_cl")
  309. colnames(joinclientcard)[9] <- c("type_cl")
  310. colnames(joinclientcard)[26] <- c("type_card")
  311. colnames(joinclientaccount)[3] <- "cl_district_id"
  312. colnames(joinclientaccount)[10] <- "acnt_district_id"
  313. colnames(joinclientacntloans)[12] <- "date_account"
  314. colnames(joinclientacntloans)[14] <- "date_loan"
  315.  
  316.  
  317. # converting
  318. ConvertCharAndIntegerVariables(joinclientaccount)
  319. ConvertCharAndIntegerVariables(joinaccountdistrict)
  320. ConvertCharAndIntegerVariables(joinclientcard)
  321. ConvertCharAndIntegerVariables(joinclientacntloans)
  322. ConvertCharAndIntegerVariables(joinclientdistrict)
  323.  
  324.  
  325. clientrating.df <- clientsdisp.df[c(1,4,6,8)]
  326. clientrating.df$cl_district_id <- joinclientaccount$cl_district_id
  327. clientrating.df$acnt_district_id <- joinclientaccount$acnt_district_id
  328. clientrating.df$diff_district <- ifelse(clientrating.df$cl_district_id != clientrating.df$acnt_district_id, 1, 0)
  329.  
  330. #client district
  331. clientrating.df$dis_avg_salary <- GetScoreForNumericVariables(joinclientdistrict$avg_salary,"p")
  332. clientrating.df$dis_unemp_rate_95 <- GetScoreForNumericVariables(joinclientdistrict$unemploy_rate_95,"n")
  333. clientrating.df$dis_unemp_rate_96 <- GetScoreForNumericVariables(joinclientdistrict$unemploy_rate_96,"n")
  334. clientrating.df$dis_commit_crimes_95 <- GetScoreForNumericVariables(joinclientdistrict$n_commited_crimes_95,"n")
  335. clientrating.df$dis_commit_crimes_96 <- GetScoreForNumericVariables(joinclientdistrict$n_commited_crimes_96,"n")
  336.  
  337.  
  338. # client type - Owner - 2, DISPONENT - 1
  339. clientrating.df$client_type <- as.numeric(revalue(joinclientdistrict$type_cl,replace = c("OWNER" = 2, "DISPONENT" = 1)))
  340.  
  341. # Card score - Gold - 3, Classic - 2, Junior - 1
  342. clientrating.df$card <- as.numeric(revalue(joinclientcard$type_card,replace = c("gold" = 3, "classic" = 2, "junior" = 1)))
  343.  
  344. # Years that the client has the card
  345. clientrating.df$year_card <- GetScoreForNumericVariables(GetAgeFromRefDate(joinclientcard$issued,refdate),"p")
  346.  
  347. # Account frequency
  348. clientrating.df$acnt_frequency <- GetScoreForFactorVariables(joinclientaccount, "frequency", c("Monthly", "Weekly", "AfterTransaction"))
  349.  
  350. # Years that the client has the account
  351. clientrating.df$year_account <- GetScoreForNumericVariables(GetAgeFromRefDate(joinclientaccount$date,refdate))
  352.  
  353. # Loans
  354. clientrating.df$loan_status <- GetScoreForFactorVariables(joinclientacntloans, "status", c("ContractFinishedDefault", "RunningInDebt", "RunningOk","ContractFinishedOk"))
  355.  
  356. # sum score
  357. clientrating.df$sum_score <- rowSums(clientrating.df[,7:18], na.rm = TRUE)
  358.  
  359. ```
  360.  
  361. Atráves do data frame gerado e com a obtenção total da soma dos escores, chegamos nessa árvore de decisão:
  362.  
  363. ```{r echo=TRUE, message=FALSE}
  364. library(rpart)
  365. library(rpart.plot)
  366. library(arules)
  367.  
  368. set.seed(1)
  369.  
  370. clientrating.df$sum_scoreD = discretize(clientrating.df$sum_score, "frequency", categories=4, labels = c("Bad", "Average", "Ok", "Good"))
  371.  
  372. flag=sample(1:nrow(clientrating.df), nrow(clientrating.df) / 2, replace = F)
  373.  
  374. clientLrn = clientrating.df[flag,]
  375. clientTst = clientrating.df[-flag,]
  376.  
  377. ac = rpart(data = clientLrn, sum_scoreD~gender+age+dis_avg_salary+dis_unemp_rate_95+dis_unemp_rate_96+dis_commit_crimes_95+dis_commit_crimes_96+client_type+card+year_card+acnt_frequency+year_account+loan_status)
  378.  
  379. prp(ac)
  380.  
  381. Dados.previsto.com.modelo<-predict(ac,clientLrn)
  382. erros.quadraticos<- (clientLrn$sum_score - Dados.previsto.com.modelo)^2
  383. erros.quadraticos
  384. erro.medio.quadratico <- sum(erros.quadraticos) / length(erros.quadraticos)
  385. (erro.medio<- erro.medio.quadratico^0.5)
  386. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement