|
| 1 | +#################################################################################################### |
| 2 | +## Title: Telco Customer Churn |
| 3 | +## Description: Data Exploration and Visualization |
| 4 | +## Author: Microsoft |
| 5 | +#################################################################################################### |
| 6 | + |
| 7 | +library(shiny) |
| 8 | +library(leaflet) |
| 9 | +library(jsonlite) |
| 10 | +library(dplyr) |
| 11 | +library(ggplot2) |
| 12 | + |
| 13 | +## Load data from SQL |
| 14 | +# cdrDF <- rxImport(inData = cdrSQL) |
| 15 | + |
| 16 | +## Load data from local |
| 17 | +cdrFile <- file.path(wd, "Data", "edw_cdr.csv") |
| 18 | +cdrDF <- read.csv(file = cdrFile, header = TRUE, sep = ",") |
| 19 | + |
| 20 | +latlonFile <- file.path(wd, "Data", "state_latlon.csv") |
| 21 | +latlonDF <- read.csv(file = latlonFile, header = TRUE, sep = ",") |
| 22 | + |
| 23 | + |
| 24 | +data <- cdrDF %>% |
| 25 | + group_by(state) %>% |
| 26 | + summarise(complaintsbystate = sum(as.numeric(numberofcomplaints)), |
| 27 | + churnbystate = sum(as.numeric(churn))) %>% |
| 28 | + mutate(lab = paste0("<center>", "state,", state, ": ", "<br>", |
| 29 | + "complaintsbystate,", complaintsbystate, "<br>", |
| 30 | + "churnbystate,", churnbystate, "</center>")) %>% |
| 31 | + left_join(cdrDF, by = "state") %>% |
| 32 | + left_join(latlonDF, by = "state") |
| 33 | + |
| 34 | +ui <- fluidPage( |
| 35 | + tags$style(HTML(" |
| 36 | + @import url('https://fonts.googleapis.com/css?family=Poppins'); |
| 37 | + |
| 38 | + body { |
| 39 | + |
| 40 | + font-family: 'Poppins', 'Lucida Grande', Verdana, Lucida, Helvetica, Arial, Calibri, sans-serif; |
| 41 | + color: rgb(0,0,0); |
| 42 | + background-color: #d2d2d2; |
| 43 | + } |
| 44 | + ")), |
| 45 | + |
| 46 | + titlePanel("Telco Customer Churn"), |
| 47 | + |
| 48 | + # Sidebar with a slider input for number of bins |
| 49 | + sidebarLayout( |
| 50 | + sidebarPanel( |
| 51 | + sliderInput("sc", "Scale size of circles (also redraws map to show only the last added state)", |
| 52 | + min = 0.5, max = 5, value = 1, step = 0.1), |
| 53 | + p(), |
| 54 | + selectInput("state", "Select a state to add to the map", |
| 55 | + choices = c("", data$state), selected = "", |
| 56 | + size = , selectize = FALSE), |
| 57 | + actionButton("clear1", "Clear all states"), |
| 58 | + p(), |
| 59 | + p("Proportion of customer churn"), |
| 60 | + plotOutput("MyPlot1", height = "200px"), |
| 61 | + p(), |
| 62 | + p("Impact of education on churn"), |
| 63 | + plotOutput("MyPlot2", height = "200px"), |
| 64 | + p(), |
| 65 | + p("Impact of call failure rate on churn"), |
| 66 | + plotOutput("MyPlot3", height = "200px"), |
| 67 | + h2("About"), |
| 68 | + HTML("<p>Created by Fang Zhou with R and Shiny leaflet. R users can download the |
| 69 | + cleaned and tidy call detail record data from <a href = 'https://github.com/Microsoft/sql-server-samples/tree/master/samples/features/r-services/Telco%20Customer%20Churn'> |
| 70 | + https://github.com/Microsoft/sql-server-samples/tree/master/samples/features/r-services/Telco%20Customer%20Churn</a>. |
| 71 | + The latitute and longitute for each USA state can be found from <a href = 'http://dev.maxmind.com/geoip/legacy/codes/state_latlon/'> |
| 72 | + http://dev.maxmind.com/geoip/legacy/codes/state_latlon/</a>.") |
| 73 | + ), |
| 74 | + |
| 75 | + |
| 76 | + mainPanel( |
| 77 | + leafletOutput("MyMap", height = 1000) |
| 78 | + |
| 79 | + ) |
| 80 | + ) |
| 81 | + ) |
| 82 | + |
| 83 | +server <- function(input, output, session) { |
| 84 | + |
| 85 | + the_data_state <- reactive({ |
| 86 | + tmp <- data %>% |
| 87 | + filter(state == input$state) |
| 88 | + |
| 89 | + if (input$state != "") { |
| 90 | + thecol <- data.frame(data)[data$state == input$state, "colour"] |
| 91 | + } else { |
| 92 | + tmp <- data[1,] |
| 93 | + thecol <- NULL |
| 94 | + |
| 95 | + } |
| 96 | + |
| 97 | + return(list(df = tmp, thecol = thecol)) |
| 98 | + }) |
| 99 | + |
| 100 | + output$MyMap <- renderLeaflet({ |
| 101 | + leaflet() %>% |
| 102 | + addProviderTiles("Stamen.Watercolor") %>% |
| 103 | + addProviderTiles("Stamen.TonerLabels") %>% |
| 104 | + fitBounds(-120, 30, -60, 50) |
| 105 | + }) |
| 106 | + |
| 107 | + observe({ |
| 108 | + leafletProxy("MyMap", data = the_data_state()$df) %>% |
| 109 | + addCircleMarkers( ~ longitude, |
| 110 | + ~ latitude, |
| 111 | + color = the_data_state()$thecol, |
| 112 | + radius = ~churnbystate * 0.1 * input$sc, |
| 113 | + popup = ~lab) |
| 114 | + }) |
| 115 | + |
| 116 | + observe({ |
| 117 | + x <- input$clear1 |
| 118 | + updateSelectInput(session, "state", selected = "") |
| 119 | + leafletProxy("MyMap") %>% clearMarkers() |
| 120 | + }) |
| 121 | + |
| 122 | + observe({ |
| 123 | + x <- input$sc |
| 124 | + leafletProxy("MyMap") %>% clearMarkers() |
| 125 | + }) |
| 126 | + |
| 127 | + |
| 128 | + output$MyPlot1 <- renderPlot({ |
| 129 | + cdrDF %>% |
| 130 | + ggplot(aes(x = factor(1), fill = factor(churn))) + |
| 131 | + geom_bar(width = 1) + |
| 132 | + coord_polar(theta = "y") + |
| 133 | + theme_minimal() |
| 134 | + }) |
| 135 | + |
| 136 | + output$MyPlot2 <- renderPlot({ |
| 137 | + cdrDF %>% |
| 138 | + group_by(month, education) %>% |
| 139 | + summarize(countofchurn = sum(as.numeric(churn))) %>% |
| 140 | + ggplot(aes(x = month, y = countofchurn, |
| 141 | + group = education, fill = education)) + |
| 142 | + geom_bar(stat = "identity", position = position_dodge()) + |
| 143 | + labs(x = "month", y = "Counts of churn") + |
| 144 | + theme_minimal() |
| 145 | + }) |
| 146 | + |
| 147 | + output$MyPlot3 <- renderPlot({ |
| 148 | + data %>% |
| 149 | + group_by(month, callfailurerate) %>% |
| 150 | + summarize(countofchurn = sum(as.numeric(churn))) %>% |
| 151 | + ggplot(aes(x = month, y = countofchurn, |
| 152 | + group = factor(callfailurerate), fill = factor(callfailurerate))) + |
| 153 | + geom_bar(stat = "identity", position = position_dodge()) + |
| 154 | + labs(x = "month", y = "Counts of churn") + |
| 155 | + theme_minimal() |
| 156 | + }) |
| 157 | +} |
| 158 | + |
0 commit comments