4 분 소요

빅데이터의 기초 지식

스크립트 언어에 의한 특별 분석과 데이터 프레임

‘데이터’는 다양한 장소에 존재하고 있으며, 그것을 수집하는 과정에서 스크립트 언어가 자주 사용된다.

데이터 처리와 스크립트 언어 - 인기 언어인 파이썬과 데이터 프레임

데이터 분석을 하려면 우선 데이터를 수집해야 한다.
파일 서버에서 다운로드하는 경우도 있지만, 인터넷 경우의 API로부터 얻을 수도 있다.
그리고 원시 데이터 그대로는 BI 도구로 읽을 수 없어 ‘전처리(preprocessing)’가 필요한 데이터도 있다.

이때 많이 사용하는 것이 스크립트 언어다.
스크립트 언어 중 인기 있는 것은 ‘R’(R 언어)과 ‘파이썬’ 두 가지다.
데이터 엔지니어 사이에서는 파이썬의 인기가 높은데 그 배경에는 다음과 같은 이유가 있다.

  • 통계 분석에 특화된 R과 비교했을 때, 파이썬은 범용의 스크립트 언어로 발전한 역사가 있고, 다양한 분야의 라이브러리를 손에 넣을 수 있다.
    특히, 외부 시스템의 API를 호출하거나, 복잡한 문자열 처리가 필요한 데이터 전처리에 적합하다.

  • 파이썬은 과할 기술 계산 분야에서 오랜 기간 사용되었고 Numpy와 SciPy라는 수치 계산용 라이브러리와 머신러닝의 프레임워크가 충실하다.
    데이터 처리 분야에서는 R에서 사용하는 ‘데이터 프레임’의 모델을 파이썬으로 만든 라이브러리인 pandas를 많이 사용하고 있다.

특히 ‘데이터 프레임’의 프로그래밍 모델은 효과적이며, 데이터 처리의 스크립트화를 생각하는 데 있어서 빠뜨릴 수 없는 존재가 되었다.

데이터 프레임, 기초 중의 기초 - ‘배열 안의 배열’로부터 작성

‘데이터 프레임(data frame)’은 표 형식의 데이터를 추상화한 객체이다.

표 형식의 데이터는 가로와 세로의 2차원 배열로 나누어져 있고, ‘배열 안의 배열’을 준비하면 데이터 프레임을 만들 수 있다.

데이터 프레임을 사용하면 스크립트 언어 안에서 데이터 가공과 집계를 할 수 있다.

웹 서버의 액세스 로그의 예 - pandas의 데이터 프레임으로 간단히 처리

예로 리스트 1.1과 같은 웹 서버의 액세스 로그를 생각해보자.
이러한 데이터는 데이터 웨어하우스와 BI 도구에서 그대로 읽어 들일 수가 없다.

리스트1.1 웹사이트의 액세스 로그
x.x.x.x - - [01/Jul/1995:00:00:01 -0400] "Get /history/apollo..." 200 6245
x.x.x.x - - [01/Jul/1995:00:00:06 -0400] "Get /shuttle/countd..." 200 3985
* 예제 데이터 'NASA-HTTP- The internet Traffic Archive'
https://ita.ee.lbl.gov/html/contrib/NASA-HTTP.html

따라서, 이 데이터를 파이썬 정규식을 사용해 파싱해보도록 한다.
다음과 같이 파일의 각 행의 분해하여 칼럼 명을 지정한다.

import re
import pandas as pd

# 로그의 각 행에 매치하는 정규 표현
pattern = re.compile('^\S+ \S+ \S+ \[(.*)\] "(.*)" (\S+) (\S+)$') 

# 정규 표현으로 파싱하는 함수(일치하지 않는 행은 그냥 버린다)
def parse_access_log(path):
    for line in open(path):
        for m in pattern.finditer(line):
            yield m.group()

# 로그 파일을 읽어서 데이터 프레임으로 변환
columns = ['time', 'request', 'status', 'bytes']
pd.DataFrame(parse_access_log('access.log'), columns=columns)
                         time                 request status bytes
0  01/Jul/1995:00:00:01 -0400  GET /history/apollo...    200  6245
1  01/Jul/1995:00:00:06 -0400  GET /shuttle/countd...    200  3985

이것으로 189만 레코드나 되는 데이터 프레임이 완성되었다.
pandas의 데이터 프레임은 메모리상에서 전개되기 때문에 수백만 행 정도의 스몰 데이터라면 매우 빠른 데이터 처리가 가능하다.

약간 데이터를 가공해보겠다.
‘time’ 칼럼의 값이 다루기 어려운 서식이므로, 표준적인 시간 포맷으로 변환한다.
여기에는 to_datetime() 함수를 사용할 수 있다.

# 데이터 프레임을 변수에 보관하기
df = pd.DataFrame(parse_access_log('access.log'), columns=columns)
# 'time' 칼럼을 덮어쓴다(타임 존 버리기).
df.time = pd.to_datetime(df.time, format='%d/%b/%Y:%X', exact=False)
# 결과 확인하기
df.head(2)
                  time                 request status bytes
0  1995-07-01 00:00:01  GET /history/apollo...    200  6245
1  1995-07-01 00:00:06  GET /shuttle/countd...    200  3985

기대하는 결과를 얻었기 때문에 CSV 파일로 보존한다.
이제 BI 도구로 읽어 들이면 시각화하는 것도 간단하다.

# csv 파일로 보관
df.to_csv('access_log.csv', index=False)
# 결과 확인하기
!head -3 access_log.csv
time,request,status,bytes
1995-07-01 00:00:01,GET /history/apollo/ HTTP/1.0,200,6245
1995-07-01 00:00:06,GET /shuttle/countdown/ HTTP/1.0,200,3985

데이터 전처리에서 사용할 수 있는 pandas의 함수

이름 설명
ix 조건에 일치하는 데이터만 검색한다.
drop 지정한 행(혹은 칼럼)을 삭제한다.
rename 인덱스 값(혹은 칼럼명)을 변경한다.
dropna 값이 없는 행(혹은 칼럼명)을 제외한다.
fillna 값이 없는 셀을 지정한 값으로 치환한다.
apply 각 칼럼(혹은 각 행)에 함수를 적용한다.

시계열 데이터를 대화식으로 집계하기 - 데이터 프레임을 그대로 사용한 데이터 집계

데이터 프레임을 사용해서 데이터를 있는 그대로 집계하는 것도 가능하다.
pandas에는 ‘시계열 데이터(time-series data)’를 취급하기 위한 다양한 기능이 있다.
시간을 인덱스로 지정함으로써 시계열 데이터를 분석할 수 있다.

스몰 데이터의 기술을 잘 사용하기

pandas는 분산 시스템이 아니기 때문에 그 자체로는 스몰 데이터는 취급할 수 있어도 빅데이터에는 대응할 수 없다.

애드 혹 데이터 분석의 효율성을 높이기 위해서는 어느 정도 데이터양을 감소시킨 후, 그 다음부터 스몰 데이터로 처리하는 것도 하나의 방법이다.

pandas를 사용하면 여러 데이터 소스부터 데이트를 읽어 들여 결합하거나, SQL과 스크립트 언어를 구분해서 사용하는 처리를 이용하는 것도 쉽게 가능하다.
스몰 데이터에는 스몰 데이터 기술을 사용하는 것이 효율적이므로 무리하게 빅데이터 기술을 사용할 필요가 없다.
# csv 파일의 로드(시간으로 파싱)
import pandas as pd
df1 = pd.read_csv('access_log.csv', parse_dates=['time'])
# 시간을 인덱스로 지정
df2 = df1.set_index('time')
# 인덱스에 의한 시간 필터링
df3 = df2['1995-07-01' : '1995-07-03']
# 1일분의 액세스 수 카운트
df3.resample('ld').size()
time
1995-07-01    64714
1995-07-02    60265
1995-07-03    89584
Freq: D, dtype: int64

데이터 프레임 분석에서는 위와 같이 새로운 변수에 차례대로 값을 대입하면서 데이터를 가공한다.

애드 혹 분석에서는 시행착오를 거치며 몇 번이고 데이터 처리를 반복하기 때문에, 이러한 변수를 잘 사용하면 조금씩 데이터 분석을 진행할 수 있다.

SQL의 결과를 데이터 프레임으로 활용하기

데이터 프레임은 쿼리를 실행한 결과로도 만들 수 있다.
이를 통해 복잡한 데이터의 집계에는 SQL을 사용하면서 데이터 프레임에 의한 대화형 데이터 처리의 혜택을 받을 수 있다.

SQLite를 이용하여 테이블을 작성하고, SQL의 실행 결과를 읽어 들이려면 다음과 같이 read_sql() 함수를 사용한다.

import pandas as pd
import sqlalchemy
engine = sqlalchemy.create_engine('sqlite://sample.db')
query = '''
SELECT substr(time, 1, 10) time, count(*) count
FROM access_log
WHERE time BETWEEN '1995-07-01' AND '1995-07-04'
GROUP BY 1 ORDER BY 1
'''
pd.read_sql(query, engine)
         time  count
0  1995-07-01  64714
1  1995-07-02  60265
2  1995-07-03  89584

실행 결과를 확인하는 부분에서는 데이터 프레임을 사용한다

-- 데이터베이스에 접속
$ sqlite3 sample.db

-- 테이블 작성
CREATE TABLE access_log (
    time timestamp,
    request text,
    status bigint,
    bytes bigint
);

-- 구분 문자 지정
.separator,

-- csv 파일로부터 로드
.import access_log.csv access_log

빅데이터의 애드 혹 분석도 기본이 되는 개념은 pandas에서 SQL을 실행하는 것과 동일하다.
데이터를 집계하는 부분에서 데이터 웨어하우스나 데이터 레이크를 이용하고 그 결과를 데이터 프레임으로 변환해두면, 그 다음은 스몰 데이터와 마찬가지로 대화형 데이터를 확인하고 가공할 수 있다.