2016년 2월 29일 월요일

웹분석 - 방문자 식별 방법

웹분석에서 방문자를 정의 한다고 할때, IP나 쿠키를 생각할 수 있다.
IP 방식은 구현이 간편하지만, IP의 유동성이나 NAT 환경에서 대표성으로 인해서 세밀하지 못하다. 일반적으로는 브라우저 단위로 세분화 가능한 쿠키 방식을 사용한다.

본문에서는 방문자 식별이 쓰이는 사례와 방법을 예시한다.

먼저 웹분석의 기본 요소를 통해서 방문자 식별 사례를 본다.

방문
최초 이벤트 발생을 시점으로 방문이 일어나고 특정 조건 하에서 방문은 유지 된다.
IDLE이 특정 시간이 지나면 방문이 끊어진 것으로 고려 할 수 있다.

방문자
쿠키에 저장된 UUID를 통해서 식별 된다.
방문 시에 식별정보가 없는 경우 UUID를 생성하고, 신규 방문자로 방문이 일어난다.
반대의 경우 재 방문자로 방문이 일어난다.

다음은 방문자 식별을 위한 UUID 생성 방법이다.

범용 고유 식별자(汎用固有識別子, 영어: universally unique identifier, UUID)는 소프트웨어 구축에 쓰이는 식별자 표준이다.
표준 형식에서 32개의 십육진수로 사용되며 8-4-4-4-12 형태와 같이 5개 그룹을 하이픈(-)으로 구분한다.

버전에 따른 생성 방식이다.
버전 1 - MAC 주소와 시간
버전 2 - DCE 보안
버전 3 - MD5 해시와 식별자이름
버전 4 - 랜덤
버전 5 - SHA-1 해시와 식별자이름

버전 4의 중복이 발생할 확률을 “생일 문제(Birthday problem)”로 계산한 예제이다.
nprobability
68,719,476,736 = 2360.0000000000000004 (4 × 10−16)
2,199,023,255,552 = 2410.0000000000005 (5 × 10−13)
70,368,744,177,664 = 2460.0000000005 (5 × 10−10)

구글 애널리틱스의 UUID는 버전 4(random)를 사용하고 있다. (가이드)
cid=35009a79-1a05-49d7-b876-2b884d0f825b

실제로 쿠키에 담긴 내용은 조금 다르다.
효율성을 위해서 randomly hash로 9자리 숫자 시간 정보 10자리 숫자를 조합한다.
예) GA1.2.699874294.1455614537
9자의 hash를 통해서 정보의 분류 용도로 활용도가 있을 것으로 보인다.

참조

생일 문제
생일 문제(生日問題)란 사람이 임의로 모였을 때 그 중에 생일이 같은 두 명이 존재할 확률을 구하는 문제이다.

n명이 있을 때의 확률
P(n) = 1 - ( 365! / ( 365**n * (365 -n)!) )
np(n)
1012%
2041%
3070%
5097%
10099.99996%
50명만 있어도 두 명의 생일이 같을 확률이 97% 이다.

위키백과
https://en.wikipedia.org/wiki/Universally_unique_identifier
https://ko.wikipedia.org/wiki/생일_문제

커버사진

2016년 2월 25일 목요일

piwik 데이터 모델 요약

오픈 소스 기반의 웹분석 도구인 PIWIK의 데이터 모델을 요약한다.

1. 데이터 생성 과정을 다룬다.
2. 테이블의 용도 및 필드명을 설명한다.
3. 테이블 명세서 시트를 기록한다.

첫번째 데이터 생성 과정이다.

가. 로그 데이터 수집 (Log Data)
나. 보관 처리 (Archiving Process)
다. 보관 데이터 생성 (Archive Data)

**
데이터 수집 대상은 4가지로 요약할 수 있다.
 - visits(방문), action types(행위), conversions(전환), ecommerce items(전자상거래)
조회 효율을 높이기 위해서 패턴 질의에 대한 보관(요약:summary) 데이터를 만든다.

2016년 2월 22일 월요일

2016년 2월 7일 일요일

전자 상거래 상품 이름 분석 II

상품 이름의 단어 조각을 트랜잭션 단위의 부분 집합(조합)으로 간주하고 연관성을 찾는 과정을 알아 본다.

본문은 자주 활용되는 연관 규칙(Association Rules)에 대한 작업 과정을 다룬다.
도구는 Python으로 전처리를 하고 분석은 R을 사용했다.

먼저 트랜잭션 데이터 소스 형태이다.

가. 장바구니 형태 (basket)
상품 이름
사각 똑딱 4P
손톱 매직 파일
헤어 집게 2P
오각 스펀지 12P
손톱 버퍼 2 세트

나. 테이블 형태 (single)
트랜잭션 단어
1 사각
1 똑딱
1
1 4P
2 손톱

두 가지 소스 중에 하나로 트랜잭션을 만든다.

가. 장바구니 형태
tr = read.transactions(“<file_name>”, format = "basket", sep=" ", rm.duplicates=TRUE)
** rm.duplicates : 트랜잭션 단위 아이탬(단어) 중복에 대한 제거 여부
     결과(return) : (중복 아이탬 수, 중복 트랜잭션 수)

나. 테이블 형태
tr = read.transactions(“<file_name>”, format = "single", sep=",", cols=c(1,2),r m.duplicates=TRUE)
** 헤더가 있는 경우 cols에 헤더 이름을 사용한다.

트랜잭션이 준비가 되었으니,

아프리오리(apriori) 알고리즘을 통해서 연관 규칙을 찾는다.

library(arules)
rules=apriori(tr, parameter=list(supp=0.01, conf=0.5))
inspect(rules)

lhs Var.2 rhs support confidence lift
1 {와이어} -> {스테인리스} 0.01001821 0.8800000 13.60901
2 {여성} -> {거실화} 0.01047359 1.0000000 54.90000
3 {거실화} -> {여성} 0.01047359 0.5750000 54.90000
4 {소스} -> {} 0.01275046 0.8000000 13.94286
5 {식탁} -> {매트} 0.01593807 1.0000000 44.81633
* lhs (Left Hand Side) - 좌변
* rhs (Right Hand Side) - 우변
* support - 지지도 = 좌우변 같이 출현한 개수 / 전제 개수
* confidence - 신뢰도 = 좌우변 같이 출한한 개수 / 좌변이 출현한 개수 = Pr(B|A)
* lift - 향상도 : 신뢰도 / 우변 지지도 = Pr(B|A) / Pr(B)

** 향상도
1을 기준으로 작으면 음의 관계 크면 양의 관계를 뜻한다.
좌우변의 지지도가 작으면서 신뢰도가 높다는 것은 좌우변의 관계가 깊다는 것을 말한다.

참고

분포 보기
library(arulesViz)
plot(rules, shading="order", control=list(main = "Words of EC Product", col=rainbow(5)))


그래프 보기
plot(rules, method="graph", control=list(type="itemsets"))

아프리오리 ( a priori )
“앞에 오는 것으로 부터”를 뜻하는 라틴어이다.
바톰 업(bottom up) 방식으로 문제에 접근 한다.
부분 집합(subset)의 빈도가 적다면 부분 집합을 포함하는 집합의 빈도도 작다는 아이디어를 활용한다.

아프리오리 in 협업적 여과 방법
http://data-rider.blogspot.kr/2016/01/blog-post_30.html

플롯(plot)에서 한글 on 맥(Mac)
par(family="AppleGothic")

코드 샘플
# 공백으로 분리된 단어를 트랜잭션 포맷으로 변경
corpus = []
tid = 0
for words in df['cleansed']:
    tid += 1
    for word in words.split():
        corpus.append((tid,word))
df = pd.DataFrame(corpus,columns=['tid','word'])

# 단어의 건수 추출
corpus = {}
for words in df['cleansed']:
    for word in words.split():
        if word not in corpus:
            corpus.setdefault(word,0)
        corpus[word] += 1
df = pd.DataFrame(list(corpus.items()),columns=['word','freq'])

# 단어의 분류 태그 달기
cmap = {
'칼라': ['블루','레드','핑크','블랙','베이지','그린','브라운','화이트','그레이'],
'사이즈': ['대','중','소'],
'재질': ['스테인리스','유리'],
'성별': ['남성','여성'],
'형태': ['원형','사각'],
'형질': ['스테인리스','유리']
}

수치 = '^(\d+\D+)+'

def flaging(word):
    for i in cmap:
        if word in cmap[i]:
            return i
    if re.match(수치,word):
        return '수치'
    return '-'

df['flag'] = df['word'].apply(flaging)

2016년 2월 5일 금요일

전자 상거래 상품 이름 분석 I

전자 상거래에 사용되는 상품 이름이 가지는 특징을 알아본다.
상품 이름은 단어(의미) 조각들로 이루어져 있고 조각들은 관계가 있을 것이다.

온라인 마켓 상품 이름을 수집한다.
상품 이름
아이스 트레이(미니)
볼메이슨 와이드 _946ML
클레어 패브릭 액자_10CMx15CM
아동용 버드 욕실화_블루
스타 미니 바스켓_3P
* 상품 이름이 친절하지 않으면 형태소 분석기를 활용하자.

상품 이름을 단어 단위로 쪼개고 태그를 부여한다.
단어
빈도
분류
단어 길이
유리 89 형질 2
세트 86 - 2
사각 86 형태 2
베이지 72 칼라 3
핑크 72 칼라 2

단어에 대한 분포이다.

빈도
단어 길이
count 1491.000000 1491.000000
mean 6.332663 3.099262
std 12.872295 1.735401
min 1.000000 1.000000
25% 1.000000 2.000000
50% 2.000000 3.000000
75% 6.000000 4.000000
max 142.000000 12.000000
* 2196 건의 상품 이름을 단어로 분리 했더니,
단어의 종류는 1491건이고 빈도는 9442 건 이었다.
* 평균 빈도와 중위 빈도의 차이를 볼 때, 일부 단어에 대한 편중이 크다.
(마치 HKR의 빈부 격차 처럼 ... )

단어 분류에 따라 흥미로운 성질들을 보인다.
분류
단어 개수
단어 빈도
빈도/개수
- 1215 6961 6
수치 258 987 4
칼라 9 764 85
사이즈 3 271 90
형질 2 231 116
형태 2 194 97
성별 2 34 17
* 상품 이름에는 상품을 분류 할 수 있는 단어들의 출현이 빈번하다.

바이그램(bi-gram)으로 빈도를 조사했다. (상위 5개)
단어 이웃
빈도
담는 아카시아 35
자주 담는 35
식탁 매트 35
원형 접시 34
동물 친구들 33

단어 바이그램에 대한 분포이다.

빈도
count 3706.000000
mean 1.955208
std 2.315853
min 1.000000
25% 1.000000
50% 1.000000
75% 2.000000
max 35.000000

빈도가 낮아서 트리그램(tri-gram) 이상은 불 필요해 보인다.
N Gram 보다는 조합 방식을 사용하면 연관성을 찾을 수 있지 않을까?

To Be Continue ...
Happy New Year 2016 with bright moon

참고

* D1 : DataFrame on Pandas Library

# 강조 컬럼에 그라디언트 적용하기
D1.style.background_gradient(cmap='magma', subset=['times'], low=1)

# 분포 명세 보기
D1.describe()

# Dict 타입 빈도 사전으로 활용하기
corpus = {}
for word in words:
    if word not in corpus:
        corpus.setdefault(word,0)
    corpus[word] += 1

# N-gram 라이브러리
from nltk.util import ngrams

# 비 문자 정규 패턴
[\W|_]+

# 수치 정규 패턴
^(\d+\D+)+

2016년 2월 4일 목요일

카이제곱 검정 실습

본문은 기 작성한 “T-Test 검정 실습”에 대한 확장된 내용을 카이제곱 검정과 함께 다룬다.

모수 검정은 표본 평균과 표본 분산을 이용하는 방법이 있다.

표본 평균의 차이를 이용하는 방법
T 분포, Z 분포
표본 분산의 차이를 이용하는 방법
F 분포, 카이제곱 분포

T-Test와 카이제곱의 공식이다.

T-TEST 공식
    ( 표본평균1 - 표본평균2 ) /  Sqrt( 표본분산1 / 표본개수1 + 표본분산2 / 표본개수2  )

카이제곱 공식
    Sum( ( 표본값 - 기대값 )**2 / 기대값 )

구현 시 주의 사항은
T-TEST 검정에서 표본분산을 구할 때는 "베셀의 수정"에 따라 표본개수에서 1개를 제외한다.
파이썬(numpy)에서는 np.var( 표본, ddof=1 )로 구할 수 있다.

핵심은
표본의 평균의 비교하는 것이 유용한가? 표본의 분산을 비교하는 것이 유용한가? 이다.
예를 들면 주사위가 잘 만들어 졌는지 검정하기 위해서 주사위를 던저서 나오는 눈금의 수를 표본으로 카이제곱 검정을 한다면 어떤가?
주사위를 60번 던졌을때 각 눈금의 기대치는 10회 이다. ( 60번 / 정6면체 )
SUM( 표본 값 (X) - 기대치 (10) )**2 / 기대치 (10) )

참고

자유도 ( Degree of Freedom, DoF)
모집단의 정보를 주는 독립적인 표본 자료의 수

DDOF (Delta Degree of Freedom, DDoF)
자유도 = 표본의 수 (N) - DDOF

베셀의 수정 ( Bessel’s Correction )
표본 관찰의 수 n이 표본 분산이나 표본 표준편차의 공식에서 n-1로 사용되는 것을 말한다.
표본의 수 n이 매우 클때는 문제가 없으나 n이 작을 때는 베셀의 수정을 통해서 모집단의 분산이나 표준편차의 추정에 발생하는 편중을 바로 잡는다.

샘플 데이터 만들기
D1 = stats.norm.rvs(loc=100,scale=1,size=50)
평균 100 편차 1인 표본 수 50개를 랜덤하게 만든다.

T-Test 함수의 사용 방법
# 표본 집단의 평균을 모집단의 평균과 비교
stats.ttest_1samp(D1, 100)
=>
( D1.mean() - 100 ) / np.sqrt(np.var(D1 - 100, ddof=1) / len(D1))
* ddof=1은 variance를 구할때, n - ddof ( n - 1) 을 뜻한다.

# 표본 집단의 비교
stats.ttest_rel(D1, D2)
=>
( D1.mean() - D2.mean() ) / np.sqrt(np.var(D1 - D2 ,ddof=1 ) / (len(D1)))

# 독립적인 표본 집단의 비교
stats.ttest_ind(D1, D2)
=>
( D1.mean() - D2.mean() ) / np.sqrt( (np.var(D1 ,ddof=1 ) / (len(D1))) + (np.var(D2 ,ddof=1 ) / (len(D2))))

카이제곱 함수의 사용방법
# D1의 평균의 분산
stats.chisquare(f_obs=D1)
=>
exp = D1.mean()
sum([ ( i - exp ) ** 2 / exp for i in D1 ])

# 표본 집단의 비교
stats.chisquare(f_obs=D1, f_exp=D2)
=>
sum(( D1 - D2 ) ** 2 / D2)

* D1, D2는 numpy의 array 타입을 사용했다.


커버 사진 (Knime)