| 팀원 소개
조사방법론2 (화, 수 C반) ‘Danatics’ 는 다음과 같은 구성원으로 이루어져 있다.
| 일정 관리
본 프로젝트의 일정은 다음과 같이 진행되었으며 주요 일정으로는 주제선정(약 3주), 데이터 수집(약 1주), 데이터 전처리(약 1주), 모델링 / 시각화(약 3주), UI/UX 디자인(약 2주) 으로 이루어 진다.
| 동일 품질
기존 고객층들이 알뜰폰을 선호하는 가장 첫번째 이유로는 동일품질 대비 저렴한 가격에 있다.
이통사의 평균 다운로드 속도와 업로드 속도는 각각 190.09 Mbps, 53.46 Mpbs 인 반면 알뜰폰의 각 속도는 188.03Mbps 와 51.88 Mbps 로 얼마 차이가 나지 않음을 확인 할 수 있다.
| 저렴한 가격
| 자급제
| 자급제
| 알뜰폰 높은 성장률
| 소비자의 불편함
| 종합 벤다이어그램
| 사업 소개
| 데이터 추출 - 소스 탐색(1) 알뜰폰 허브, 모두의 요금제 모요, 플러스 알파
| 데이터 추출 - 소스 탐색(2) - 알뜰폰 허브
| 데이터 추출 - 리스틀리(1)
리스틀리란 크롬 웹 브라우저 확장자 프로그램 중 하나로 웹 페이지 크롤링에 특화되어 있는 확장자 프로그램이다.
사용방법
| 데이터 추출 - 리스틀리(2)
| 데이터 추출 - 변수설정
추출한 데이터 파일은 다음과 같다.
알뜰폰 Hub 에서 주어진 10가지 변수 중 분석에 필요하지 않는 변수들을 제외하고, 다음과 같은 변수를 추가적으로 사용하였음.
| 전처리 및 변수 생성 - 전처리 전 사진
| 전처리 및 변수 생성 - 전처리 후 사진
[전처리 코드]
library(dplyr); library(readr) ;library(dplyr); library(tidyr); library(stringr)
options(max.print=1000000)
a<-matrix(NA, nrow=890, ncol=5)
#전처리 값 넣기 위한 행렬 생성
#전처리 파일 불러오기
library(readxl)
Ntel <- read_excel("C:/Users/chlwo/OneDrive/바탕 화면/전처리/Ntel.xlsx")
for (i in 1:890) {
a[i,1]<-str_replace(gsub('GB|G|일|[+]','',(Ntel[i,5] %>% str_sub(start=1, end=4))),"MB|M","/1000")
#데이터에서 영단위 삭제, 특수문자 삭제, 메가바이트의 경우 단위값 계산을 위해 1000 나눠주기.
a[i,2]<-as.numeric(gsub('무제한','10000',gsub('분','',Ntel[i,6])))
#음성 변수에 문자열 분 삭제, 무제한의 경우 3사 기준 월 10000시간 을 무제한 요금으로 지정하고 있음
a[i,3]<-as.numeric(gsub('무제한','2000',gsub('건','',Ntel[i,7])))
# 문자 변수에 문자열 건 삭제, 무제한의 경우 3사 기준 월 2000건을 무제한 요금으로 지정하고 있음.
a[i,4]<-as.numeric(gsub(',','',gsub('원','',Ntel[i,8])))
#4번 가격에 통신료 추가
a[i,5]<-as.numeric(gsub('\\D', '',gsub('[[]','',gsub('LGU|SKT','7', Ntel[i,10] %>% str_sub(start=1, end=4)))))
#더보기란 중 프로모션 기간만을 필요로함. 대부분 프로모션 기간이 앞 쪽에 강조되어 있으므로 앞자리 추출 후 문자열 삭제
}
data<-data.frame(a)
#전처리값 데이터 프레임으로 전환
names(data)<-c("data", "call", "Message", "price","dod")
#행에 변수 네이밍
data[c(1:30),c(1:5)] ;#상위 30개 추출
## data call Message price dod
## 1 7 10000 2000 4060 5
## 2 15 100 100 12110 5
## 3 11 10000 2000 17600 5
## 4 100 10000 2000 24200 5
## 5 1.5 300 100 3080 <NA>
## 6 2 200 100 3190 <NA>
## 7 5 300 100 5940 <NA>
## 8 5 500 500 6930 <NA>
## 9 8 200 100 7480 <NA>
## 10 10 100 100 8590 <NA>
## 11 10 200 200 9150 <NA>
## 12 10 300 100 9570 <NA>
## 13 10 400 100 10120 <NA>
## 14 2.2 100 50 0 7
## 15 3 100 50 550 7
## 16 1 250 100 990 7
## 17 1 500 50 990 7
## 18 4 100 50 1100 7
## 19 2.5 200 100 1300 7
## 20 5 100 50 3850 7
## 21 5 200 50 4400 7
## 22 5 250 100 5500 7
## 23 6.5 100 50 6600 7
## 24 6 250 100 6820 7
## 25 8 180 100 6920 7
## 26 7 250 100 7130 7
## 27 2 200 100 3190 <NA>
## 28 3.5 200 100 4160 5
## 29 10 100 100 8590 <NA>
## 30 10 200 200 9150 <NA>
write.csv(data, file= "C:/Users/chlwo/OneDrive/바탕 화면/전처리/찐처리.csv")
#저장
| 할인율 가격 적용
| 회귀 변수
| Score 변수 생성
| 가중치 산출방법에 따른 고객만족도지수의 비교
[회귀분석 코드]
library(lm.beta);library("caret");library("car");library("dplyr");library("MASS");library(readr)
전처리 <- read_csv("C:/Users/chlwo/OneDrive/바탕 화면/회귀분석 가중치/전처리.csv")
#다중회귀분석
price.lm<-lm(price~data+Message+call, data=전처리) ; summary(price.lm)
##
## Call:
## lm(formula = price ~ data + Message + call, data = 전처리)
##
## Residuals:
## Min 1Q Median 3Q Max
## -20954 -5767 -1938 4078 32065
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8166.8369 406.0923 20.111 < 2e-16 ***
## data 184.5529 9.1610 20.145 < 2e-16 ***
## Message 2.8299 1.2471 2.269 0.02349 *
## call 0.6908 0.2397 2.881 0.00405 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 8851 on 886 degrees of freedom
## Multiple R-squared: 0.5496, Adjusted R-squared: 0.5481
## F-statistic: 360.4 on 3 and 886 DF, p-value: < 2.2e-16
#다중 회귀분석 계수값 표준화
lm.beta(price.lm)
##
## Call:
## lm(formula = price ~ data + Message + call, data = 전처리)
##
## Standardized Coefficients::
## (Intercept) data Message call
## NA 0.4775314 0.1948473 0.2474997
#가중치값 생성
y<-NULL
w<-NULL
for(i in 1:3){
y[i]<-lm.beta(price.lm)$sta[i+1]
} ;for(i in 1:3) {
w[i]<-(y[i]/sum(y))
r<-rbind(y,w)
}
## Warning in rbind(y, w): number of columns of result is not a multiple of vector
## length (arg 2)
colnames(r)<-c("데이터","음성","문자");r
## 데이터 음성 문자
## y 0.4775314 0.1948473 0.2474997
## w 0.5191245 0.2118185 0.2690570
#표준화 계수
| 샤이니 화면 -
| 모델링 알고리즘 도형
[요금제 제시 과정] - 먼저 그림의 ’계산기’는 추천할 요금제를 도출해주는 함수들의 집단으로 shiny server 내부에서 설계되었다. 1. 계산기가 요금제별 데이터, 음성, 문자량을 가지고 score라는 변수 값을 부여한다. 2. 이 중 모든 score 값을 사용하지 않고, 사용자 제공 정보를 기준으로 ± 10000원의 요금제만을 계산에 이용한다. 3. 사용자 요금제의 score와, 요금제 열에서 추출된 socre 값의 차를 구한 후 절댓값을 취하여 오름차순 정렬 후 상위 10개의 요금제를 제시해준다.
| 고객정보 (1)
| 고객 정보(2) - 추천 요금제
| 회원가입 예시
| 저장된 고객정보
[동적 추천 데이터 Shiny 구현]
# Sys.setlocale("LC_ALL","C")
# Sys.setlocale("LC_ALL","Korean") ##run only one time
library(shiny)
library(xlsx)
library(DT)
rm(list = ls())
ui <- fluidPage(
titlePanel("Recommand"),
sidebarLayout(
sidebarPanel(
textInput(inputId = "in_name",label = "Name:",value="kim"),
numericInput(inputId ="in_promotion",label = "Remain promotion:",value = "5"),
textInput(inputId = "in_phonenumber",label = "Phonenumber:",value="010-xxxx-xxxx"),
hr(),
hr(),
numericInput(inputId ="in_price",label = "Price:",value = "15000"),
numericInput(inputId ="in_message",label = "Message:",value = "200"),
numericInput(inputId ="in_call",label = "Call:",value = "500"),
numericInput(inputId ="in_data",label = "5G/LTE(GB):",value = "500"),
hr(),
hr(),
numericInput(inputId = "in_target",label = "Price that you want:",value = "20000"),
actionButton("update","Load")
,actionButton("go","View(After load)")
),
mainPanel(
h3(paste("Recommand for you")),
tableOutput(outputId="out_target"),
dataTableOutput(outputId = "out_table")
)
)
)
############################
server<-function(input,output){
printTarget<-reactive({
if(input$update ==0){
if(input$in_name!="kim"){dir.create(paste0("C:/",input$in_name,"/"))
return()}}
isolate({
input$update
customer<-data.frame(name=input$in_name,term=input$in_promotion,phonenumber=input$in_phonenumber,current_price=input$in_price,want=input$in_target)
write.xlsx(customer,file=paste0("C:/",input$in_name,"/information for ",input$in_name,".xlsx"),append=FALSE,col.names=FALSE,row.names=FALSE)
write.xlsx(info1(),file=paste0("C:/",input$in_name,"/Recommand for ",input$in_name,".xlsx"),append=FALSE,col.names=FALSE,row.names=FALSE)
})
})
info1<-reactive({
extract_calling_plan<-function(){
key_number<-top()
int_key<-as.numeric(key_number)
return_dataframe<-matrix(ncol=ncol(integration)-1,byrow = TRUE)
for(i in 1:10){
next_dataframe<-matrix(data=NA,nrow=1,ncol=ncol(integration)-1,byrow = TRUE)
for(j in 1:nrow(integration1)){
if(int_key[i]==integration1[j,1])
next_dataframe[1,1:10]<-integration[j,1:10]
}
return_dataframe<-rbind(return_dataframe,next_dataframe)
}
return(return_dataframe[2:11,])}
limit<-function(k){
upper_limit<-0;lower_limit=0;
if(k>=10000){
upper_limit<-k+10000;lower_limit<-k-10000
}
else{
upper_limit<-k+10000;lower_limit<-0
}
return(c(upper_limit,lower_limit))
}
isolate({
price_ex<-function(){
weightprice<-data.frame(c(),stringsAsFactors = FALSE)
limit_outcome<-limit(input$in_target)
lower_limit<-limit_outcome[2];upper_limit<-limit_outcome[1]
for (i in 1:nrow(scorematrix)){
if(scorematrix[i,4]>=lower_limit&&scorematrix[i,4]<=upper_limit){
weightprice[i,1]<-scorematrix[i,5]}
}
return(weightprice)
}
})
top<-function(){
return(c(calling_plan_number[1:10]))
}
integration<-read.csv(paste0("C:/cheapPhone/10.csv"),header=T)
preprocessing<-read.csv(paste0("C:/cheapPhone/10preprocessing.csv"),header=T)
data<-c(as.numeric(preprocessing[,2]))
call<-c(as.numeric(preprocessing[,3]))
message<-c(as.numeric(preprocessing[,4]))
price<-c(as.numeric(preprocessing[,5]))
a<-5;b<-2;c<-3
score<-matrix(a*data+b*call+c*message,ncol=1,byrow=F)
data_cus<-input$in_data;call_cus<-input$in_call;message_cus<-input$in_message;#price_cus<-input$in_price;
isolate({
data_cusNu<-as.numeric(data_cus);call_cusNu<-as.numeric(call_cus);message_cusNu<-as.numeric(message_cus);#price_cusNu<-as.numeric(price_cus);
score_cus<<-a*data_cusNu+b*call_cusNu+c*message_cusNu
})
scorematrix<-data.frame(data,call,message,price,score,stringsAsFactors = FALSE)
targetscore<-data.frame(c(),stringsAsFactors = FALSE)
targetscore<-abs(score_cus-price_ex())
targetscore_plus<-data.frame(1:nrow(targetscore),targetscore[,1],stringsAsFactors = FALSE)
rmtargetscore<-as.matrix(targetscore_plus[complete.cases(targetscore_plus),])
testsort<-as.matrix(sort(rmtargetscore[,2]))
calling_plan_number<-rownames(testsort)
integration1<-data.frame(1:nrow(integration),integration,stringsAsFactors = FALSE)
result<-extract_calling_plan()
return(result)
})
printScreen<-reactive({
if(input$go==0){return()}
isolate({
input$go
screen<-read.xlsx(paste0("C:/",input$in_name,"/Recommand for ",input$in_name,".xlsx"),1,header=FALSE)
colnames(screen)<-c("Company","Line","5G/LTE","Target","Data","Call","Message","Price","Agr","etc")
rownames(screen)<-c("1st","2nd","3rd",paste0(4:10,"th"))
screen
})
})
output$out_target<-renderTable({printTarget()})
output$out_table<-renderDT({printScreen()})
}
shinyApp(ui,server)
위 3개의 그림은 신상 요금제 알리미 서비스를 네이버 오픈 api를 활용한 문자 전송 매크로를 이용해 엑셀 파일로 구현한 모습이다.
고객명과 번호를 적어 요금제 리스트가 갱신되는 매월 1일에 문자를 발송하여 고객에게 알린다.
| 알리미 문자 확인
| UI / UX 디자인
| UI / UX 디자인
[디자인 설명]
신뢰감을 표현하기 위해 푸른계열의 색을 주로 사용하였으며, 시중 앱을 참고하여 직관적인 디자인을 선보일 수 있도록 노력하였다.
또한 회원가입 창에는 여러 계정과의 연동을 통해 로그인이 가능하도록 디자인 하여 사용자의 편의성을 증대하였다.
알뜰폰 알리미의 가장 큰 역할인 요금제 확인란 진입 과정에서는, 한페이지를 추가적으로 삽입하여, 사용자로 하여금 요금제 추천을 기대할 수 있는 장치를 마련하였다.
앱사용이 즐거울 수 있도록, 터치가 즐거운 일이 될 수 있도록 디자인 하는 것이 알뜰폰 알리미 앱의 궁극적 목표이다.
[알뜰폰 알리미 어플 UI/UX 디자인] Link: 알뜰폰 알리미 어플 디자인
#####
**요금제 추천 서비스
이동통신사 3사에서 사용자 데이터 기반 최적 요금제를 고지하게 되었다는 내용의 지난주 일자 기사이다.
하지만 이미 유럽에서는 2020년부터 최적 요금제 고지를 시행하고 있는 반면에 우리나라는 3년이 지난 지금에서야 국내에서 첫 고지 서비스를 시행하게 되었다.
이렇게 된 배경에는 전기통신사업법이 과거 유선 전화기 시절에 머물러 있어 현재에 맞게 규정되지 않았기 때문이며, 또한 아직 국내에서는 공공데이터에 대한 규제 완화 및 범망 마련이 미비되어 있어 활용할 데이터를 받아 볼 수 없었기 때문이다.
| 데이터 규제 완화 - (1)
| 데이터 규제 완화 - (2)
그러나 지난 9월 부터 국가데이터 정책 위원회가 데이터 분야 8개 및 총 13개의 규제 개선이 시행되었고 규제 완화가 됨과 동시에 공공데이터와 사기업의 데이터를 융합하여 고객 만족 생활밀착형 맞춤 서비스를 시행하려는 움직임을 보이고 있다.
현 상황에서 알뜰폰 알리미는 국가 주도 데이터 규제 완화 및 법망 마련에 힘입어 공공데이터와 알뜰폰 알리미 벤쳐 데이터를 결합 한다면 그 활용 방안은 무궁무진 할 것으로 기대된다.