파이썬 분석 실무, 유저 Funnel 분석 - (5) 데이터 전처리

|

python 분석 실무, 유저 funnel 분석

데이터 전처리

나중에 데이터를 탐색하거나, 데이터를 프로세싱을 진행할 때 편하도록 전처리를 진행한다. 여기에서는 데이터 값 중 같은 항목을 하나의 이름으로 통일시키고, 불필요하게 긴 데이터를 짧게 줄였다.

확장자명 통일

  • .value_counts()
    • 해당 값들 항목별 숫자 출력해줌
  • .replace(dict)
    • 미리 지정해둔 값으로 교체
    • 바꾸고 싶은 값만 dict으로 지정하여 교체할 수 있음
df.ext.value_counts()

# PDF      82004
# DOCX     58303
# XLSX     52118
# HWP      26244
# DOC      24586
# XLS      24489
# PPTX     15385
# TXT       9814
# PPT       5382
# PPSX      2374
# ODT        820
# PPS        324
# JPG          9
# SHEET        5
# WORD         2
# PNG          2
# Name: ext, dtype: int64

ext_dic = {'DOCX': 'DOC',
           'XLSX': 'XLS',
           'PPTX': 'PPT',
           'PPSX': 'PPT',
           'PPS': 'PPT',
           'ODT': 'TXT',
           'PNG': 'JPG'
          }

df['ext'] = df['ext'].replace(ext_dic)
df.ext.value_counts()

# DOC      82889
# PDF      82004
# XLS      76607
# HWP      26244
# PPT      23465
# TXT      10634
# JPG         11
# SHEET        5
# WORD         2
# Name: ext, dtype: int64

신규 session_id 부여

필수는 아니나, 계산량 감소를 위해 텍스트 사이즈 감량 진행

  • DataFrame.ix[]
    • 데이터프레임의 정보를 인덱스로 호출 하는 속성값
    • [_] 내부 인자로 숫자와 함께 칼럼명 같이 사용이 가능함
    • DataFrame.loc[], DataFrame.iloc[]와 같은 indexer이지만, 숫자와 칼럼명같이 쓰는데에 유용함.
    • 한 행씩 돌면서 값에 처리를 할 때 유용함

.ix is exceptionally useful when dealing with mixed positional and label based hierarchical indexes.

pandas 0.23.4 documentation

s = [] # empty list
j = 0 # default setting

# loop
for i in range(len(df)-1):
    
    if df.ix[i, 'sessionid'] == df.ix[i+1, 'sessionid']:
        s.append(j)
    else:
        s.append(j)
        j += 1

실습 파일 확인하기

파이썬 분석 실무, 유저 Funnel 분석 - (4) 예측 모델을 통한 결측치 처리

|

python 분석 실무, 유저 funnel 분석

결측값에 예측모형으로 예측치 넣기

결측치를 다루는 방법 중 적절성은 비교적 높으나 별도의 모형과 계산량이 필요하다.

1. 데이터 준비

  • sklearn(사이킷런)을 이용함
  • ind_cols
    • 예측하고 싶은 값에 영향을 주는 요소 중 서로 독립적인 칼럼명만 넣어둔다.
    • train, test, predict 데이터 x 값에 바로 넣기 편하다.
    • DS school에서 배울 때에는 상관도를 이용하여 영향 없는 칼럼을 골랐었다.
# fill na using predictive model

# train without na
df_msl = df_ms.dropna()

# set independent cols  <-- 서로 영향 없는 칼럼만 고르기

ind_cols = ['actiontype', 'ismydoc', 'ext', 'screen']

#split ind, tar --> 학습시키고 싶은 칼럼과 인풋 칼럼 나누기
x = df_msl[ind_cols]
y = df_msl[['documentposition']]

2. 항목값 전처리 - Label Encoder

Label Encoder는 독립 변수가 아닌 종속 변수(라벨)에 대해 사용한다. 문자열이나 정수로된 라벨 값을 0 ~ K−1 까지의 정수로 변환한다. 변환된 규칙은 classes_ 속성에서 확인할 수 있다. 예측 결과에 적용할 수 있도록 역변환을 위한 inverse_transform 메서드도 지원한다. 출처

인코딩이란? 인코딩은 카테고리 값이나 텍스트 정보를 처리가 쉬운 정수로 변환하는 과정이다.

예전에 배웠을 때에는 ‘One-Hot-Encoder’를 사용했었음 One-Hot-Encoding은 항목형 데이터를 해당 항목 칼럼을 만들고 해당하는 값에만 정수 1을 넣어주는 방식이다. 참고

from sklearn.preprocessing import LabelEncoder

encoder = LabelEncoder()

X = x.apply(lambda x: encoder.fit_transform(x))
y = y.apply(lambda y: encoder.fit_transform(y))

# .inverse_transform()를 이용해서 역방향도 가능하다.

3. 훈련데이터와 평가데이터 추출하기

train_test_split는 데이터의 표본을 무작위로 추출해 훈련 데이터와 평가 데이터로 나눈다. 이때 random_state 속성값을 이용해서 적절히 섞은 곳에서 추출할 수 있다. (그냥 하는 경우 정렬되어 있거나 할 때 그 비율에 맞춰 추출될 가능성이 있는 것 같음 - 자세히 찾아봐라) 참고

from sklearn.model_selection import train_test_split

# X: df_ms_ind / y: df_ms_tar
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10)

4. 학습모형 만들기 - KNN Algorithm

k-최근접 이웃 알고리즘(또는 줄여서 k-NN)은 분류나 회귀에 사용되는 비모수 방식이다. 특정한 공간내(X 값에 따라 결정) 내 k개의 가장 가까운 훈련 데이터를 가지고 해당 값을 예측하는 모델

  • k-NN 분류에서 출력은 소속된 항목이다. 객체는 k개의 최근접 이웃 사이에서 가장 공통적인 항목에 할당되는 객체로 과반수 의결에 의해 분류된다(k는 양의 정수이며 통상적으로 작은 수). 만약 k = 1 이라면 객체는 단순히 하나의 최근접 이웃의 항목에 할당된다.
  • k-NN 회귀에서 출력은 객체의 특성 값이다. 이 값은 k개의 최근접 이웃이 가진 값의 평균이다.

검증 표본(초록색 원)은 첫 번째 파랑 네모의 항목이나 빨강 삼각형의 두 번째 항목으로 분류되어야 한다. 만약 “k = 3” (실선으로 그려진 원)이면 두 번째 항목으로 할당되어야 한다. 왜냐하면 2개의 삼각형과 1개의 사각형만이 안쪽 원 안에 있기 때문이다. 만약 “k = 5” (점선으로 그려진 원)이면 첫 번째 항목으로 분류되어야 한다. (바깥쪽 원 안에 있는 3개의 사각형 vs. 2개의 삼각형)

참고 텐서플로우 knn

from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=5).fit(X_train, y_train)

5. 학습모형 평가하기 - Score

  • 학습을 통해 만들어진 예측 모형에 평가 데이터를 넣어 실제값과 얼마나 유사하게 예측하는지 평가한다.
  • 즉, X를 넣어 나온 predicted Y가 넣어준 Y와 맞는지 확인
  • 즉, 스코어는 해당 모델의 예측 정확도를 확인할 수 있음
print(knn.score(X_test, y_test))

6. 학습모형 평가하기 - 분류 성능 평가(sklearn.metrics)

분류 문제는 회귀 분석과 달리 다양한 성능 평가 기준이 필요하다.

  • 분류 결과표 Confusion Matrix
    • 분류 결과표는 타겟의 원래 클래스와 모형이 예측한 클래스가 일치하는지는 갯수로 센 결과이다.
    • 원래 클래스는 행(row)으로 예측한 클래스는 열(column)로 나타낸다.
  • 이진 분류 결과표 Binary Confusion Matrix
    • 클래스가 0과 1 두 종류 밖에 없는 경우에는 일반적으로 클래스 이름을 “Positive”와 “Negative”로 표시한다.
    • 또, 분류 모형의 예측 결과가 맞은 경우, 즉 Positive를 Positive라고 예측하거나 Negative를 Negative라고 예측한 경우에는 “True”라고 하고 예측 결과가 틀린 경우, 즉 Positive를 Negative라고 예측하거나 Negative를 Positive라고 예측한 경우에는 “False”라고 한다.
    • 통계에서 1종 오류, 2종 오류 확인하는 것과 비슷하다
    • 정보
      • precision(정밀도) : 전체 중에 잘 맞게 들어간 비율
      • recall(재현도) : 진짜 중에 진짜라고 분류된 것 비율
      • Fall-Out (위양성율) : 가짜 중에 진짜라고 분류된 것 비율
      • f1-score : precision(정밀도)와 recall(재현도)을 함께 고려한 값
      • support : 그 값으로 예측된 항목 수
#행열에서 대각선 부분 외에는 잘 못 예측한것임
from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_test, knn_pred))
# [[ 4733     0     0     0     3     0     0]
#  [    2 13895     0     0     0     0     0]
#  [    0     0  1920     0     3     0     0]
#  [    0     0     2  1085     0     0     0]
#  [    1     0     1     0 53383     0     0]
#  [    0     1     0     0     0   413     0]
#  [    0     3     0     0     0     0    19]]


from sklearn.metrics import classification_report

print(classification_report(y_test, knn_pred))
#             precision    recall  f1-score   support
#
#           0       1.00      1.00      1.00      4736
#           1       1.00      1.00      1.00     13897
#           2       1.00      1.00      1.00      1923
#           3       1.00      1.00      1.00      1087
#           4       1.00      1.00      1.00     53385
#           5       1.00      1.00      1.00       414
#           6       1.00      0.86      0.93        22
#
# avg / total       1.00      1.00      1.00     75464

7. 결측값에 예측치 채워 넣기

# 인코딩에서 숫자로 변환되었던 항목값 
class_cd = pd.Series(encoder.classes_).to_dict()

# 결측치가 하나 이상 있는 Case만 선택
df_ms_only = df_ms[df_ms.isna().any(axis=1)]
# 결측치가 없는 Case만 선택
df_ms_dropna = df_ms.dropna()

# 평가에 필요한 칼럼만 뽑으면서, 동시에 인코딩 진행
df_ms_only[ind_cols].apply(lambda x: encoder.fit_transform(x))
# 학습모형에 집어 넣어 값 예측하기
knn.predict(df_ms_only[ind_cols].apply(lambda x: encoder.fit_transform(x)))
# 예측값 저장하기
fill_na_values = knn.predict(df_ms_only[ind_cols].apply(lambda x: encoder.fit_transform(x)))

# 결측치가 있는 곳에 예측값 집어 넣기
df_ms_only['documentposition'] = fill_na_values

# 인코딩된 칼럼값을 되돌리기
df_ms_only['documentposition'] = df_ms_only['documentposition'].replace(class_cd)

#원래 데이터에 합치기
df_ms_final = pd.concat([df_ms_dropna, df_ms_only], axis=0)

실습 파일 확인하기

파이썬 분석 실무, 유저 Funnel 분석 - (3) 결측치 처리

|

python 분석 실무, 유저 funnel 분석

결측치 처리(Missing Value)

결측치를 어떻게 처리할 것인가는 결측치의 수량, 데이터 타입, 그리고 결측값의 원인에 따라 다르다. 전체 샘플의 수가 많다면 상대적으로 적은 결측값을 버릴 수도 있고, 데이터의 타입이 연속되어 있는 시간이라면 앞뒤 중간 값을 넣을 수 있다. 데이터를 합치면서 새로운 데이터를 만드는 경우, 예를 들어 결제 내역 로그를 바탕으로 일별 결제건수를 정리한다면 결제건수 중 결측값이 있는 곳은 결제 내역이 없는 즉 0개의 결제가 일어난 날로 보고 0으로 결측값을 채워 넣기도 한다. 또한 결측값을 채워 넣을 정보가 없는 경우, 결측값이 없는 데이터들을 바탕으로 결측값을 모델링을 통해 예측하여 넣을 수 있다.

  • dropna()
    • 샘플수가 많다면 missing values 를 포함하는 행을 모두 삭제하는 것이 가능함
# 결측치가 하나라도 있으면 버리는 코드 예제
df.dropna()

# 모든 값이 Null일 경우만 버리는 코드 예제
df.dropna(how='all')

# 결측치가 두개 이상인 경우 버리는 코드 예제
df.dropna(thresh=2)

# 해당 column의 결측치가 있는 것을 선택하여 버리는 코드 예제
df.dropna(subset=['name', 'born'])

# 결측치가 하나 이상 있는 Case만 선택하는 코드 예제
df[df.isnull().any(axis=1)]
  • fillna()
    • 샘플수가 충분하지 않을 경우, 이 명령어를 이용해 Null값을 채우는 것이 가능하다.
    • 연속형인 경우 Mean값이나 Median을 이용하고, 명목형인 경우 Mode(최빈치)를 이용한다.
    • 결측값이 없는 데이터를 이용해 예측 모형을 만들어 Null 값을 채워 넣을 수 있다.
# frequency table  - 가장 빈도가 높은 것부터 차근차근 나온다
df_ms.documentposition.value_counts()

# OTHERAPP          213775
# MYPOLARISDRIVE     55518
# LOCALSTORAGE       18922
# NEWDOCUMENT         7612
# NONE                4335
# OTHERCLOUD          1617
# SHAREDDOCUMENT        76
# Name: documentposition, dtype: int64

# fillna with most frequent value (MODE)
freq_values = df_ms.documentposition.value_counts().index[0]

df_ms['documentposition'] = df_ms['documentposition'].fillna(freq_values)

실습 파일 확인하기

파이썬 분석 실무, 유저 Funnel 분석 - (2) 날짜 데이터 다루기

|

python 분석 실무, 유저 funnel 분석

날짜 데이터 다루기

데이터 분석시 날짜 데이터를 활용하면 편하게 시간에 따른 추이 분석이 가능하다. 요일별, 날짜별, 월별, 년도별 그리고 시간별까지 쪼개어 트렌드를 살펴볼 수 있다. 그 중 유의미한 시간기준이 무엇인지 찾는 것이 시간 데이터를 다뤄 얻어내야 할 목표이다.

  • pandas.to_datetime() : 날짜 데이터로 변경 참고
  • Pandas Datetime API
  • .dt.year
  • .dt.month
  • .dt.date
  • .dt.day
  • .dt.dayofweek : 0-Monday, 6-Sunday
df["datetime"] = pd.to_datetime(df["datetime"])

df.info()
# <class 'pandas.core.frame.DataFrame'>
# Int64Index: 301861 entries, 0 to 301860
# Data columns (total 7 columns):
# actiontype          301861 non-null object
# ismydoc             301861 non-null object
# ext                 301861 non-null object
# sessionid           301861 non-null object
# documentposition    301861 non-null object
# datetime            301861 non-null datetime64[ns]
# screen              301861 non-null object
# dtypes: datetime64[ns](1), object(6)
# memory usage: 18.4+ MB

df["datetime"].dt.month[:5]
# 0    7
# 1    7
# 2    7
# 3    7
# 4    7

df["datetime"].dt.day[:5]
# 0    18
# 1    18
# 2    18
# 3    18
# 4     6
  • 날짜데이터 다룰 때 유용한 .groupby()
  • gropyby 해서 나온 결과를 dataframe으로 바꾸고 싶을 때
    • pandas.DataFrame() : index가 gruopby의 기준 칼럼 값이 된다.
    • pd.DataFrame().reset_index() : index에 0부터 넣고, 기준 칼럼이 하나의 칼럼으로 들어가게 한다.
# 날짜별 날짜의 갯수를 확인하는 코드
df.groupby('datetime').size() 

# 날짜별로 세션 수를 계산하는 코드
df.groupby("datetime")['sessionid'].nunique()

# groupby로 나온 결과의 index를 칼럼으로 넣고, index에는 정수를 넣는 코드
pd.DataFrame({'counts': df.groupby('datetime').size()}).reset_index()

실습 파일 확인하기

파이썬 분석 실무, 유저 Funnel 분석 - (1) 데이터 불러오기

|

python 분석 실무, 유저 funnel 분석

데이터 불러오기

  • .read_csv() :csv 데이터 불러오기
  • 항상 불러오면 아래 내용을 확인하는 습관을 갖을 것
    • .shape : 데이터의 사이즈 확인
    • .head(),.tail() : 실제 데이터 앞뒤로 확인, 앞부분은 df[:10]로도 확인이 가능하다.
    • .info() : 데이터 타입, 결측치 확인
    • .isna().sum() : 데이터 결측값이 있는 것의 수 확인
df = pd.read_csv("df_funnel.csv", index_col = 0)

df.shape
# (301861, 7)

df.info()
# <class 'pandas.core.frame.DataFrame'>
# Int64Index: 301861 entries, 0 to 301860
# Data columns (total 7 columns):
# actiontype          301861 non-null object
# ismydoc             301861 non-null object
# ext                 301861 non-null object
# sessionid           301861 non-null object
# documentposition    301861 non-null object
# datetime            301861 non-null object
# screen              301861 non-null object
# dtypes: object(7)
# memory usage: 18.4+ MB

df.head(5) 
# actiontype	ismydoc	ext	sessionid	documentposition	datetime	screen
# 0	OPEN	NoView	PDF	9400fd2e43d7dc2d054ca78806236ee1	LOCALSTORAGE	2016.7.18	Per_Dir
# 1	CLOSE	NoView	PDF	9400fd2e43d7dc2d054ca78806236ee1	LOCALSTORAGE	2016.7.18	Per_Dir
# 2	OPEN	View	PDF	9400fd2e43d7dc2d054ca78806236ee1	MYPOLARISDRIVE	2016.7.18	Pub_Dir
# 3	CLOSE	View	PDF	9400fd2e43d7dc2d054ca78806236ee1	MYPOLARISDRIVE	2016.7.18	Pub_Dir
# 4	OPEN	NoView	PDF	f191063c562691041dfa935ff0876975	OTHERAPP	2016.7.6	Main

df.isna().sum()
# actiontype          0
# ismydoc             0
# ext                 0
# sessionid           0
# documentposition    0
# datetime            0
# screen              0
# dtype: int64

실습 파일 확인하기