|
1. Main question
다양한 장비/서비스에서 일어나는 시스템 데이터를 통해 사용자의 불편을 예지하기 위해 ‘시스템 데이터’와 ‘사용자 불편 발생 데이터’를 분석하여 불편을 느낀 사용자와 불편 요인들을 찾아주세요.
2. Data set
train_err_data.csv
16,552,664 rows, 784,263kb
train_problem_data.csv
5,430 rows, 117kb
합쳐서 용량이 770메가라서 올리지 못했습니다. 하단의 사이트에서 받았습니다.
출처: 데이콘. LG - 시스템 품질변화로 인한 사용자 불편예지
https://dacon.io/competitions/official/235687/data/
3. 테이블 생성
maria db에 테이블을 생성합니다.
- 컬럼명 확인
head train_err_data.csv
- (1) train_err_data 테이블 생성
create table train_err_data
(user_id int,
time varchar(30), 시간이 20201101025616식으로 되어있습니다. int로 만들 시 에러가 발생합니다.
model_nm varchar(30),
fwver varchar(30),
errtype varchar(30),
errcode varchar(50)); 에러발생해서 50으로만들었습니다.
LOAD DATA LOCAL INFILE '/home/scott/train_err_data.csv'
REPLACE
INTO TABLE orcl.train_err_data
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(user_id, time, model_nm, fwver, errtype, errcode);
- (2) train_problem_data 테이블 생성
컬럼명 확인
head train_problem_data.csv
create table train_problem_data
(user_id int,
time varchar(30))
LOAD DATA LOCAL INFILE '/home/scott/train_problem_data.csv'
REPLACE
INTO TABLE orcl.train_problem_data
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(user_id, time)
- (3) 컬럼명 분석
해당 컬럼명이 무엇인지, 해당자료가 무엇을 나타내는지, 어느 제품에 대한 자료인지 아무것도 주어지지 않았습니다.
때문에 모든 것을 추측해야 합니다.
- train_err_data
user_id : 유저번호. 10000번부터 24999번까지 나열된 것을 볼 때, 총 15000명. 특정 번호를 부여한 것이 아니라 접수된 순서대로 인 것 같습니다. 1655만개 데이터로 인당 평균 약, 1100개의 에러 수준을 가집니다.
time : 에러가 발생한 시각(연월일24시분초)
model_nm : 모델명. 0번부터 8번까지 총 9가지 모델이 존재합니다.
select distinct model_nm from train_err_data; 로 확인했습니다.
fwver : 펌웨어 버전으로 추정. 동일 유저인데 fwver번호가 바뀐 이후 나타나던 에러가 사라지는 것을 발견했습니다.
errtype : 에러타입. 29를 제외하고 1부터 42까지 존재 각 번호가 어떤 에러를 의미하는지 알 수 없습니다.
select distinct errtype from train_err_data order by cast(errtype as unsigned)
errcode : 세부에러. 2805종류입니다. 숫자와 영문을 혼용하고 있습니다. 0, 1, 2 등의 숫자와, 'connection timeout'. 'NFANDROID2', standby 등이 혼재되어 있습니다. NFANDROID의 경우 검색해본 결과 셋톱박스와 관련이 있는 것으로 보여집니다.
- train_problem_data
문제에 나와있는 사용자 불편발생 데이터로 추측됩니다. user_id와 time으로 구성되어져 있습니다.
문제를 제기한 사람들로 추정되는데 시간은 연월일24시인데 분초는 버림되어있습니다. 순서는 유저아이디도, time도 아니고 뒤죽박죽입니다. 1시간에 한번 문제를 제기된 사람들을 종합한 자료로 추정됩니다.
2.1) 문제발생
마리아db에서 조인을 걸었는데 먹통이 되었습니다. 파이썬에서 불러오는데 리소스가 부족한지 꺼져버렸습니다.
데이터가 너무 대용량이어서 문제가 되는 것 같았습니다.
그래서 대용량에 적합한 하이브로 다시 테이블을 생성하여 작성하였습니다.
- 하이브에서 테이블 작성
create table train_err_data
(user_id int,
time string,
model_nm string,
fwver string,
errtype string,
errcode string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
먼저 텍스트 파일로 만들고 ORC로 만듭니다.
load data inpath '/user/scott/train_err_data.csv'
overwrite into table train_err_data;
파일 저장포맷을 ORC로 만듭니다. 데이터를 컬럼단위로 처리하여 처리속도를 높일 수 있습니다.
create table train_err_data 1
(user_id int,
time string,
model_nm string,
fwver string,
errtype string,
errcode string)
STORED AS ORC
LOCATION '/user/scott/train_err_data1;
데이터를 넣습니다.
insert overwrite table train_err_data1 select * from train_err_data;
하이브 검색엔진을 tez로 하고, 데이터 처리방식을 벡터화를 사용했습니다. 한번에 1024행을 처리할 수 있습니다.
set hive.execution.engine=tez;
set hive.vectorized.execution.enabled=true;
problem데이터는 데이터양이 많지 않기 때문에 ORC로 만들지 않았습니다.
3. 데이터 정리 및 시각화
train_err_data는 총 데이터셋이고 train_problem_data는 그 중 문제를 제기한 사람들의 데이터일 것입니다.
train_err_data를 train_problem_data와 join해서 문제를 제기한 사람들과 문제를 제기하지 않은 사람들의 데이터, 그리고 총 데이터 3개로 분리하였습니다.
- 기본 데이터 : train_err_data
- 문제제기한 사람데이터 : err11(inner join)
hive -e "select q.user_id, q.errtype,q.errcode from train_err_data q inner join train_problem_data w on (w.user_id=q.user_id);" > /home/scott/err11.csv
- 문제제기하지 않은 사람 데이터 : err12(left join where user_id(problem_data에서 나온) is null)
hive -e "select q.user_id, q.errtype,q.errcode from train_err_data q left join train_problem_data w on (q.user_id=w.user_id) where w.user_id is null;" > /home/scott/err12.csv
1) 모델별 에러 숫자를 확인
모델의 에러숫자이지만, 모델별 에러 횟수가 정규분포를 따른다고 했을 때, 낮은 모델이 더 많이 팔렸기 때문에 높은 숫자가 나왔다고 볼 수 있을 것입니다. 즉 추측하건대 모델 숫자가 높아질수록 하이엔드 모델이라고 보여집니다. 또한 비싼 모델의 경우 품질에 좀 더 신경을 쓰는 경향이 있으므로 모델 0~4와 모델 5~8의 격차가 더 크게 벌어졌을 거라고 보여집니다.
-코드
hive -e "select model_nm, count(*) cnt from train_err_data group by model_nm order by model_nm;" > /home/scott/err2.csv
df = pd.read_csv("/home/scott/err2.csv",sep='\t',header=None)
df=df[:-1]
df.columns=['model_nm','cnt']
df["model_nm"] = [i for i in range(0,9)]
plt.xticks(np.arange(0,9))
plt.bar(df['model_nm'],df['cnt'])
2) 시간대별 문제제기 숫자를 확인
LG 콜센터의 영업시간은 오전9시~오후6시까지 입니다. 그 외에 인터넷 접수의 경우 24시간 접수를 받습니다.
영업시간 외에 접수는 대개 인터넷 접수로 보입니다.
시간별 problem 데이터는 낮시간이 확실히 많습니다. LG콜센터는 9~6입니다. 업무시간에 접수가 이뤄지는 것인데 콜센터 시간을 지나서 한밤중에 문제를 접수한다는 것은 다음날 콜센터를 기다리기 어려울 정도로 화가 났기 때문에 불편을 감수하고 늦은 시간에 접수를 한 것이 아닐까 싶습니다. 따라서 밤시간이 좀 더 심각한 문제들이 아닐까? 라는 가설을 세우고 있습니다.차후 데이터 검증 프로세스에서 검증해 보아야 할 것 같습니다.
마리아db를 파이썬으로 불러와서 확인
import pandas as pd
import mysql.connector
config = {
"user": "root",
"password": "1234",
"host":"192.168.56.101",
"database":"orcl",
"port":"3456"}
conn = mysql.connector.connect(**config)
cursor=conn.cursor()
sql = """ SELECT substr(time,9,2) times, count(*) cnt
from train_problem_data
group by times
order by times"""
cursor.execute(sql)
resultList = cursor.fetchall()
df = pd.DataFrame(resultList)
df.columns = ['time', 'cnt']
print(df[['time', 'cnt']])
plt.bar(df['time'],df['cnt'])
3) 전체 데이터 중 errtype별 에러숫자를 확인
특정에러가 많아보입니다. 에러가 많은데도 불구하고 문제제기 건수가 적다면(비율이 낮다면) 문제가 있지만 불편한 정도에 그치는 에러일 것입니다. 에러가 적은데도 불구하고 문제제기 건수가 많다면(비율이 높다면) 사용에 치명적인 문제일 가능성이 클 것입니다. 확인하기 위해 문제제기하지 않은 사람 대비 문제제기한 사람을 다음에 보겠습니다. 또한 데이터가 많은 errtype순서대로 상관분석하여 그 정도가 없거나 미미하다면 변수를 제거하여 연산속도 향상을 꾀해볼 수 있을 것 같습니다.
import pandas as pd
import mysql.connector
config = {
"user": "root",
"password": "1234",
"host":"192.168.56.101",
"database":"orcl",
"port":"3456"}
conn = mysql.connector.connect(**config)
cursor=conn.cursor()
sql = """ SELECT errtype, count(*) cnt
from train_err_data
group by errtype
order by errtype"""
cursor.execute(sql)
resultList = cursor.fetchall()
df = pd.DataFrame(resultList)
df.columns = ['errtype', 'cnt']
print(df[['errtype', 'cnt']])
plt.bar(df['errtype'],df['cnt'])
df = pd.read_csv("/home/scott/err11.csv",sep='\t',header=None)
df12 = pd.read_csv("/home/scott/err12.csv",sep='\t')
df.columns=['user_id','errtype','errcode']
df12.columns=['user_id','errtype','errcode']
temp = []
for i in range(1,43):
temp.append(len(df[['user_id','errtype']][df['errtype']==i]))
print(temp)
temp2 = []
for i in range(1,43):
temp2.append(len(df[['user_id','errtype']][df['errtype']==i]))
print(temp2)
temp1 = pd.DataFrame(temp1)
temp2 = pd.DataFrame(temp2)
temp0=[]
temp0 = pd.DataFrame(temp0)
temp0['df_problem'] = temp1['errtype']
temp0['df_noproblem'] = temp2['errtype']
ax = temp0.plot(kind='bar')
3-1) barplot 비교
두 데이터를 비교하였는데 눈에 띄는 것은 errtype 3, 14, 22, 26, 27번 정도이고 유의미한 차이는 잘 보이지 않습니다. 작은 데이터의 경우 위 그래프로 비교가 어려우므로 숫자로 알아보도록 하겠습니다.
3-2) 비율로 비교
barplot으로 만들었으나 유의미한 결과가 보이지는 않았습니다.
이번에는 비율로 비교해보겠습니다.
비율로 보니 상관관계가 뚜렷한 변인들이 보입니다. 문제제기O/문제제기X 비율을 보니 barplot에서 보지 못한 25,18,20번 에러의 경우 엄청나게 큰 차이가 존재하는 것을 볼 수 있습니다. 각각 9.68배, 8배, 7.57배가 넘게 많이 발생했습니다. 치명적인 에러들로 보입니다. 일정 비율 이상의 에러들은 상관관계가 높을 것이고, 반대로 에러 비율이 낮은 변수들은 거의 무해한 에러들일 확률이 높습니다. 이상값을 확인한 후, 제거해도 무방할 듯 합니다.
그러나 이상값 몇개가 모든 에러를 떠안고 있다면 제거하면 안됩니다. 이상값을 제거한 후 비율을 다시 확인해야 합니다. 추후에 이상값 체크가 필요해 보입니다.
result = []
result=pd.DataFrame(result)
result['row'] = [i for i in range(1,43)]
result['rate'] = temp00['df_problem']/temp00['df_noproblem']
result.sort_values(by=['rate'],axis=0,ascending=False,na_position='last')
result = result.sort_values('rate', ascending = False)
print(result)
4) 유저당 에러 횟수
앞에서 유저별 이상값이 떠올랐기 때문에 유저당 에러횟수를 확인하였습니다. 전체 15000명의 user_id에서 에러 횟수 상위 10% 유저가 문제를 제기한 비율을 먼저 확인했습니다. 예상 외로 문제를 제기한 비율은 크지 않았기 때문에 유저당 에러횟수는 큰 영향력이 없구나 하고 넘어가려다가 혹시나 해서 하위 10% 비율을 확인했습니다.
에러발생건수 하위 10%문제제기 비율은 확연히 적었습니다. 문제가 발생하는 횟수가 적다면 당연히 문제제기 건수도 적을 것입니다. 이에 저는 10%당 문제제기 비율을 확인하였습니다.
눈으로 보이듯이 에러 발생건수가 늘어나면 문제제기비율도 비례하여 증가하는 것을 볼 수 있습니다.
문제제기 비율은 상위 10%만 두고보면 영향력이 적어 보였으나 사실은 비례하는 관계를 가지는 것으로 볼 수 있습니다.
5) 그 외
time 관련
- 시간은 11월 한달동안 수집된 데이터로 보입니다. time의 시작시간이 20201031일이며 끝 시간이 20201202입니다.
때문에 특정 유저들은 충분한 데이터가 수집되지 못했을 수 있습니다. 유저별 에러횟수를 확인해본 결과 가장 적은 에러를 발생시킨 유저는 1건으로 적은 숫자가 아니며 꽤 많은 수였습니다.
- train_problem_data의 문제가 제기된 시간 이후의 데이터는 폐기하는 것이 불필요한 노이즈를 줄일 수 있는 방법이 될 수 있습니다.
- 사용자가 문제를 제기하기 전 며칠이 가장 큰 문제가 발생했을 가능성이 있습니다. 예를 들어 problem_data에 등록된 시간 3일 전, 그 이후를 비교하여 특정한 에러가 발생했는지 확인하는 것도 좋은 방법이 될 것입니다.
fwver 관련
- 펌웨어 버전은 불만제기와 밀접한 관계를 가지고 있을 것입니다. 펌웨어 업데이트를 하고나서 문제제기를 하는 경우가 있을 것이고 업데이트를 하지 않아서 문제제기를 하는 경우가 있을 것입니다. 그러나 앞으로 나올 펌웨어가 어떤 버그를 가지고 있을지는 예측할 수 없습니다.
또한 해당 펌워어에 의한 효과는 에러코드와 중복될 것입니다. 어떠한 펌웨어 업데이트 이후 특정 에러가 발생한다면 특정 에러코드가 누적될 것이기 때문입니다. 그러므로 회귀분석에서 다중공선성 문제를 가질수 있습니다.
따라서 저는 펌웨어 변수를 이용하지 않기로 하였습니다.
|