아래의 글은 elice(엘리스) 에서 진행한 인공지능/머신러닝 맛보기 수업을 듣고 개인 공부를 목적으로 정리한 글입니다. 학습자료가 따로 있기에 그림이나 예제등 자세한 내용 없이 키워드와 기억하고 싶은 내용, 궁금해서 따로 검색해 놓은 내용만 적어놓은 것임을 밝힙니다.
이상 탐지 & 추천 알고리즘
정규분포
Normal Distribution
Gaussian Distribution
자연에서 발생하는 데이터를 설명하는 방법 중 하나
사람의 키
기계에서 만들어내는 물건들의 크기
측정치(오차 포함)
시험 점수
보통 Bell curve를 그린다. 이런 분포들을 “정규분포를 따른다” 라고 한다.
초기에 Bean Machine - “Quincunx” or “Galton Box” 를 활용해 밑에 떨어진 공의 개수가 정규분포를 따른다는 사실을 도출해냄
σ(sigma) = Standard deviation, “표준 편차” 이전 강의에 나온 분산은 sigma의 제곱이다.(σ²) - 데이터가 퍼져있는 정도 작을 수록 데이터가 덜 퍼져있다는 것을 의미. N(μ, σ²) 위의 N은 Normal Distribution을 나타낸다. 평균 μ(mu-뮤)는 정확히 중간을 가리킨다.
1차원 데이터를 히스토그램을 활용해서 시각화하는 방법이 있다. 히스토그램이 정규분포를 표현한다.
트레이닝한 모델을 활용해서 원하는 데이터가 나올 확률이 적다면 이상점(anomaly) 으로 판단할 수 있다.
Gaussian Mixture Model (GMM)
두 개 이상의 데이터 모델이 섞여 있는 경우 어떤 데이터가 있을 때 각각의 모델에 매치될 확률을 찾을 수 있다. 2차원에 점을 찍으면 등고선처럼 구분할 수 있다. 분산이 크면 등고선이 넓고 각각의 모델은 클러스터로 구분이 된다. 평균(등고선의 정상)에 가까울수록 해당 모델일 확률이 높아진다.
협업 필터링(Collaborative Filtering)
두 가지 방법 이 있다.
유저 기반 협업 필터링 - 예)당신과 비슷한 사람은 이 영화를 봤으니 당신도 좋아할거에요.
아이템 기반 협업 필터링 - 예)당신이 봤던 영화들과 비슷한 영화들은 당신도 좋아할거에요.
유저 기반 협업 필터링
유저간의 유사도를 구한다.(벡터를 활용 - 각각의 데이터 벡터를 모아 매트릭스(matrix)를 만든다)
코사인 유사도 : 두개의 벡터 사이에 각도를 본다. 각도가 작을 수록 높은 유사도를 갖는다.
유사도를 고려하여 각 영화에 대해 다른 유저의 추천도를 계산한다.
각 유사도를 활용해 각 유저별 점수의 평균 수치를 활용한다.
아이템 기반 협업 필터링
다른 사람에게 선택 됐는지 안됐는지를 통해 수치를 계산 하는 것
아이템간의 비교(유저간 비교와 비슷하지만 벡터를 아이템별로 만든다)
각 아이템의 유사도를 고려하여 아이템을 추천한다.
평가 기반
평가를 기반으로 계산 평가 수치를 가지고 계산하는 것으로 위의 단순하게 1과 0(영화를 봤는지 안봤는지)으로 나누는 것보다 더 효율적일 확률이 높다. 마찬가지로 유저 기반 협업 필터링과 아이템 기반 협업 필터링으로 나눌 수 있다. 중요한 것은 평가를 하지 않았다를 0으로 두면 안된다는 것이다. 평가하지 않은 것은 어떤 평가를 할 지 모르는 것이고 0을 주는 것은 나쁘게 평가하는 1과 비슷하므로 엄연히 다른 값이다. 평가가 되지 않은 Missing Data는 보통 평균값을 대입하고, 수치에 변별력이 없다고 판단되면 다른 방식 혹은 데이터마다 알맞은 값을 넣어서 계산을 한다.
참고 해볼만한 자료
Netflix Prize Data
총정리
머신러닝
지도 학습
Linear Regression(선형 회귀법)
Classification(분류) - Naive Bayes(나이브 베이즈)
비지도 학습
Dimension Reduction(차원축소) - PCA
Clustering(클러스터링) - K-Means
Hard Clustering : K-Means
Soft Clustering : GMM
추천 시스템
Collaborative Filtering(협업 필터링)
안배운 개념
Reinforcement Learning(강화 학습)
Optimization(최적화)
Batch Learning(한번에 배운다)
Online Learning(천천히 배운다)
SVM Support Vector Machine(서포트 벡터 머신) - 지도 학습 분류에 좋다
Deep Learning(딥러닝) - 보통 지도 학습의 분류에 사용
그 외에 무수히 많다.
마치며
그 동안 4번의 강의를 통해 인공지능과 머신러닝에 대한 대략적인 개념과 활용범위를 배웠습니다. 사실 지금 당장 사용할 지식을 배운 것은 아닙니다. 그러나 이번 코스를 통해 개발자와 수학에 대한 연결고리를 느낄 수 있었고, 앞으로 개발자 커리어에 대한 고민을 많이 해볼 수 있는 기회였습니다. 언제나 그렇듯 지식은 한번에 새로운 것들을 이루기 위한 것이라기 보다는 기반으로 삼아 응용하고 발전하기 위해 활용되는 것으로도 충분히 가치가 있다고 생각합니다. 앞으로도 다양한 분야의 지식을 쌓고 발전시켜 폭넓게 사고할 수 있는 개발자가 되려고 노력할 것입니다.
위의 코드가 PCA를 구현한것. N차원을 num_components차원으로 줄여준다. scikit-learn을 활용.
데이터 표준화
표준화(Normalization)는 여러 뜻을 가지고 있다. 이번엔 데이터를 [0..1]의 범위로 조정하는 것을 의미 이유는 스케일(Scale) 따라 주성분의 방향이 바뀌기 때문에 모든 특성(Attribute)의 스케일을 같게 할 필요가 있다.
K-means 클러스터링
반복을 이용한 클러스터링 알고리즘
중심 Centroid : 각 클러스터의 “중심”을 의미
중심과의 거리 distance : 중심과 데이터 포인트와의 거리
K-means Step
초기 중심값은 데이터 중 임의로 선정
두개의 중심점과 각각의 다른 점들과의 거리를 구해서 거리가 가까운쪽의 중심점의 그룹으로 분류한다.
형성된 그룹(클러스터)에서 중심점을 다시 계산한다. 여러가지 방식이 있지만 오리지널은 포인터 위치의 무게중심값으로 정한다.(평균으로 하기도 한다)
다시 각각의 데이터 포인트에 대해 위에서 계산된 중심점과의 거리를 구해 가까운 중심점을 찾는다.
모든 데이터 포인트에 대해 가장 가까운 클러스터를 할당한다.
데이터 포인트의 클러스터 할당이 새로 진행되지 않을때가지 3번부터 반복한다.
K-means의 문제점
빠르고 강력한 만큼 문제점이 존재한다.
K(클러스터 개수)값에 따라 결과값이 완전히 달라진다.
초기값에 예민하게 반응한다.
비구형 클러스터에서 잘 동작하지 못한다.
위의 문제점에 따른 해결책
여러 K값을 시도해본다. 이것을 체크하기 위한 알고리즘 : 실루엣 Silhouette: 모든 데이터 포인트가 클러스터에 얼마나 잘 분류되었는가를 수치화하는것. A : 한 데이터와 같은 클러스터내 다른 포인트 사이의 평균 거리 B : 이 데이터와 이웃 클러스터 내 다른 포인트 사이의 평균거리 A <<< B 일수록 좋은것.
다른 초기값과 함께 알고리즘을 반복 실행 최고의 silhouette 점수를 가진 클러스터를 선택
다른 알고리즘을 사용한다.
문서 벡터화
정제 Bag of Words 모델을 단어 순서가 있는 1차원 벡터로 변환하는 과정(단어순서는 아무렇게나)
전체 데이터에서 단어 카운트
전체 데이터에서 50개 미만인 단어는 제거
전체 데이터에서 50개 이상인 각 단어에 인덱스 할당
문서 내에서 인덱스가 있는 단어의 단어 카운트
마치며
인공지능&머신러닝을 공부하며 다시한번 느낀건데 파이썬 라이브러리들은 정말 대단한 것 같습니다. 파이썬이 왜 데이터 사이언스에서 중요해졌는지를 느끼게된 시간이었습니다. 이번 시간에선 고차원의 데이터를 시각화를 위해 저차원으로 줄이는 과정이 무척 인상적이었습니다. 간단히 라이브러리를 불러와서 적용하고, 처리한 데이터들을 조합해서 원하는 결과물을 만들어내는 과정을 보면 레고가 연상됩니다. 이는 데이터 사이언스라는 학문의 특성인것 같습니다. 개발자는 새로운 알고리즘을 만들거나 코드 하나하나 의미를 부여하며 더 나은 성능을 위해 노력한다면, 데이터 사이언티스트는 라이브러리들을 활용해 데이터를 분석하고 다양한 예측모델을 만들어내는 노력이 필요한 것 같습니다. 결국 원하는 것이 무엇이고, 목표를 위해 주어진 재료가 무엇이며, 어떻게 효율적으로 활용할 것인가 하는 문제를 끊임없이 생각하고, 더 나은 선택을 위해 지식과 경험을 넓혀 나가야겠다는 다짐을 했습니다.
아래의 글은 elice(엘리스) 에서 진행한 인공지능/머신러닝 맛보기 수업을 듣고 개인 공부를 목적으로 정리한 글입니다. 학습자료가 따로 있기에 그림이나 예제등 자세한 내용 없이 키워드와 기억하고 싶은 내용, 궁금해서 따로 검색해 놓은 내용만 적어놓은 것임을 밝힙니다.
확률론 & Naive Bayes 분류기
확률이란?
어떤 사건이 일어날 것인지 혹은 일어났는지에 대한 지식 혹은 믿음 을 표현하는 방법
Early Probability Theory
사실은 도박으로 시작된 학문 게임을 해서 돈 내기를 했는데 중간에 게임이 중지되었다. 그 돈을 나누는 과정에서 확률 이론이 정립. 처음엔 그동안 이긴 횟수로 나눠서 상금을 나눠갖는 것이 어떨까? (Luca Pacioli) -> 최종 승리를 위해 나머지 경기의 결과를 확률로 계산해서 나눠야 한다.(Blaise Pascal)
확률 기초
합집합 : P(A ∪ B)
교집합 : P(A ∩ B)
조건부 확률 : P(A | B) = P(A ∩ B) / P(B) : 사건 B가 일어났을 때 A가 일어날 확률
확률로 π 구하기 -> 정사각형에 내접하는 원을 그리고 수많은 점을 찍어서 원 안에 들어오는 확률을 활용해 파이(π)를 구할 수 있다.(Monte Carlo(유명한 도박사-다양한 확률론 정립) 방법)
베이지안 확률(Bayesian probability) / 통계론
빈도 주의자 vs 베이즈 주의자
“동전 하나를 던졌을 때 앞면이 나올 확률은 50%이다.”
빈도 주의자 : 이 동전을 수천, 수만번 던졌을때 그중 앞면이 50%, 뒷면이 50%나온다. -> 경험주의적
베이즈 주의자 : 동전 던지기의 결과가 앞면이 나올 것이라는 확신(혹은 믿음) 이 50%이다.
분류기 주어진 데이터가 어떤 클래스에 속하는지 알아내는 방법을 자동으로 학습 하는 알고리즘
P(A|X)와 P(B|X) 를 비교하면 어떤 것이 더 클까? P(A|X) : P(B|X) = P(X|A)P(A) / P(X) : P(X|B)P(B) / P(X) = P(X|A)P(A) : P(X|B)P(B)
결과값이 아주 작아서 비교가 힘들경우 두 값이 더해서 1이 되도록 표준화(Normalize)를 거쳐서 눈으로 비교하기 좋도록 표시한다.
Likelihood(우도/가능도)
우리가 만든 모델이 관측값을 만들어낼 확률 P(X|A) : X - observation(관측), A - model
Bag-of-Words
처리과정 오늘 나는 밥을 먹었다. 어제 나는 햄버거를 먹었다. -(특수 문자 제거) -> 오늘 나는 밥을 먹었다 어제 나는 햄버거를 먹었다 -(Tokenize) -> 오늘/나는/밥을/먹었다/어제/나는/햄버거를/먹었다
순서는 중요하지 않음.
단점 : 문장이 사라지고 단어들만 남는다. 간단한 분석은 이정도로 충분. 기존 문장정보를 가지고 있는 기술도 있다.
감정 분류기(Sentiment Classifier)
위의 Naive Bayes 분류기처럼 긍정과 부정 집단을 만든다. 긍정/부정 BoW 는 어떻게 알아내야 하나? -> 기계학습 알고리즘으로 자동으로 학습하도록 한다. 학습방법은 긍정적인 문서 묶음과 부정적인 문서 묶음을 다 조사해서 각각의 문서 셋들에서 나오는 단어의 빈도 수를 측정시킨다. 각각의 BoW를 만드는것.
단어가 없으면 어떻게 할까? 0이 나오면 모든 확률이 0으로 변해 망한 모델이 된다. -> 엄청나게 작은 수를 대입시켜서 다른 단어에 영향을 미치지 않도록 한다. 이런 방식을 Smoothing 이라고 한다.
마치며
이번 시간엔 이론 공부와 실제로 데이터를 다루는 실습이 같이 이루어지면서 앞에서 배웠던 개념들을 “왜?” 그리고 “어떻게?” 사용하는지 코드로 확인해보았습니다. 많은 데이터들을 분류하고 10년 전에 배운 확률에 대한 개념을 다시 끄집어내면서 수학에 대한 흥미를 다시 불러일으켰습니다. 사실 어렸을 때 제일 좋아했던 과목이 수학과 체육이었는데, 어느 순간 수학이 사회에서 쓸데가 있을까 하고 생각했던 적이 있었을 만큼 현실세계와의 접점을 찾지 못했었는데, 이번 수업들을 통해 그 접점이 채워져서 너무 만족스럽습니다.(전공이었던 전자공학을 공부할때는 현실세계와의 접점이라기 보다는 전공공부라고 생각했던것도 문제였고.. ㅎㅎ) 꼭 인공지능이나 머신러닝쪽이 아니더라도 개발자로써 수학공부에 다시 열정을 불러일으키게된 계기가 되었습니다. 어렸을 때 심심하면 수학문제를 풀던 그 시절 알고리즘과 코딩을 알았으면 어땠을까하는 아쉬움도 남지만 그 아쉬움을 연료로 삼아 앞으로 꾸준히 다양하게 공부하기로 다짐합니다.
아래의 글은 elice(엘리스) 에서 진행한 인공지능/머신러닝 맛보기 수업을 듣고 개인 공부를 목적으로 정리한 글입니다. 학습자료가 따로 있기에 그림이나 예제등 자세한 내용 없이 키워드와 기억하고 싶은 내용, 궁금해서 따로 검색해 놓은 내용만 적어놓은 것임을 밝힙니다.
데이터 사이언스
데이터 중심의 과학 데이터에서 지식과 통찰력을 발견하는 과학적인 방법론.
통계학
데이터 분석
머신러닝
예전의 데이터 사이언스
부제 : 데이터 사이언스의 시초 19세기 중반 영국 런던에서 콜레라 발병 -> 콜레라는 왜 그리고 어떻게 전파되는가?(존 스노우(왕좌의 게임 아님)) - 가설만 하지말고 검증을 해보자 -> 지도에 발병자를 표시해보자 -> 콜레라로 인한 사망자는 한 펌프를 기준으로 퍼진다. 다른 펌프를 이용한 사용자는 사망하지 않음. -> 콜레라를 옮기는 매개체는 공기가 아니라 물이다. 데이터로 인한 검증
머신 러닝
명시적으로 프로그래밍을 하지 않고도 컴퓨터가 학습할 수 있는 능력을 갖게 하는 것
데이터 마이닝 데이터가 주어졌을 때 사람들이 얻을 수 있는 정보를 뽑아내는 것.
Feature 학습 어떤 사물이나 생물의 사진을 수십, 수백만장을 보여주고 답을 알려주면 학습을 통해 공통적인 특징(feature)을 도출해냄
추천 사용자 개개인에게 추천을 하여 원하는 정보를 제공해 주는 것.
무엇을 할 수 있나?
지도 학습
비 지도 학습
강화 학습
지도 학습(Supervised Learning)
훈련 데이터(Training Data)로부터 하나의 함수를 유추해내기 위한 기계 학습(Machine Learning)의 한 방법. 간단히 말하면 학습을 지도한다고 생각하면 될 것 같습니다. 어떤 대표적인 데이터에 대한 답을 정해주면 그 데이터와 답을 통해 미래의 어떤 대상을 추론할 수 있게 알고리즘을 적용 시키는 방식이라고 할 수 있습니다.
회귀 문제 회기분석(regression analysis)은 관찰된 연속형 변수들에 대해 두 변수 사이의 모형을 구한뒤 적합도를 측정해 내는 분석 방법.
분류 문제 새로운 데이터가 어떤 클래스(class)에 해당하는지 판단하는 것. 데이터는 여러개의 차원을 가질 수 있습니다.
비지도 학습
군집화 지도학습과 반대로 답을 내릴 수 없는 경우 컴퓨터에게 데이터를 입력하면 컴퓨터가 특정 군집(Cluster)으로 데이터를 나눕니다. 나누어진 군집을 보고 사람이 후에 그 군집에 대한 정의를 내려줍니다.
강화 학습
어떤 환경 안에서 정의된 에이전트가 현재의 상태에서, 선택 가능한 행동들 중 보상을 최대화하는 행동 혹은 행동 순서를 선택하는 방법(출처 : Wikipedia)
위에서 에이전트는 게임 케릭터가 될 수도 있고, 알파고가 될 수도 있습니다. 보상은 승리 혹은 게임아이템이라고 할 수 있으며, 어떤 행동을 해야 더 좋은 보상을 얻는지에 대한 순서를 선택하도록 하는 학습법 입니다.
Numpy
Numpy는 Python에서 사용되는 과학 컴퓨팅용(Scientific Computing) 라이브러리 입니다.
Python 언어에서 기본으로 지원하지 않는 행렬과 같은 데이터 구조 지원 및 수학 / 과학 계산 함수 포함하고 있습니다.
행렬이 필요한 이유 : 머신러닝에서 대부분의 데이터는 행렬로 표현됩니다.
행렬 만들기
1 2 3 4
import numpy as np A = np.array([[1, 2], [3, 4]]) print(A)
이렇게 만들어진 행렬은 곱셈, 덧셈, 뺄셈이 가능합니다. 행렬 내 원소에 대한 산술 연산(element-wise operation)도 가능합니다. 비교, 논리 연산도 가능합니다. (우리가 생각하는 대부분의 수학 연산이 가능한듯 합니다.)
Numpy 활용해보기
1 2 3 4 5 6
import numpy as np A = [[1, 2],[3, 4]] print(A) # [[1,2],[3,4]] A = np.array(A) print(A) # [[1 2] # [3 4]]
N : 데이터의 개수 X : “Input” 데이터 / Feature Y : “Output” 해답 / 응답 (X^(i), Y^(i)) : i번째 데이터
Loss Function : 차이의 제곱의 합
단순 선형 회귀분석 (Simple Linear Regression)
다중 선형 회귀분석 (Multiple Linear Regression) 은 데이터의 여러 independent variables (features) XX로부터 response variable YY를 예측하는 모델입니다.
다항식 회귀분석 : 2차식 X^2 를 X2로 치환해놓고 생각하면 다중 회귀 분석과 동일해집니다.
성능 측정 방법
RSS(Sesidual Sum of Squares) : 전체 데이터에서 실제 값과 모델이 예측하는 값의 차이(클 수록 나쁨)
MSE(Mean Squared Error) : 평균적으로 각 데이터의 실제값과 모델이 예측하는 값의 차이(클 수록 나쁨)
R^2 : r = Pearson’s correlation coefficient 상관관계를 r수치로 표현하는 방식
마치며
거창한줄 알았던 인공지능과 머신러닝을 맛보니(?) 생각보다 접근하기 어려운 학문이 아니라는 사실을 알게 되었습니다. 고등학교와 대학과정에서 수학을 꾸준히 공부했다면 무난하게 공식이나 개념을 이해할 수 있는 수준이라고 생각합니다. 물론 더 발전적이고 전문적인 분야는 새로운 알고리즘과 접근방식, 공식 등 연구가 필요한 분야는 맞습니다. 하지만 막연한 두려움만 가지고 있는 분이라면 예전에 배운 수학지식을 조금만 끌어올려서 다가가도 불가능한 영역은 아니라고 생각합니다. 엘리스(elice)수업을 통해 접하게 되어 기쁘고 쉽게 설명해 주신 김수인 강사님에게 감사의 말씀전합니다. 앞으로 적어도 지금 듣고 있는 수업내용을 정리하면서 맛보기 시리즈를 연재하여 배운 내용이 쉽게 흩어지지 않도록 복습할 계획입니다.
데이터 베이스란 단어는 개발자가 아니어도 많이 듣는 용어중 하나 입니다. 의미는 데이터들을 잘 정리하여 모아놓은 것이라고 할 수 있습니다.
개발자들은 데이터 베이스에 많은 관심을 가져야 합니다. 데이터를 얼마나 잘 관리하고 효율적으로 사용하는지가 사업의 연속성에 큰 영향을 주기 때문입니다. 이번 글은 데이터 베이스에 관해 공부한 것을 간략히 정리하겠습니다.
데이터가 중요한 이유
데이터는 회사또는 서비스의 자산입니다. 물론 무조건 많다고 좋은 것이 아닙니다. 그 이유는 데이터를 저장하고 있는 것 자체도 비용을 지불하기 때문입니다. 데이터를 담고 있는 서버의 용량 혹은 데이터들이 네트워크 상으로 이동하면서 사용하는 통신 비용 등을 예로 들 수 있습니다. 따라서 데이터는 최소한으로 필요한 것만 모으는 것이 좋습니다. 아래의 사진을 보며 더 깊이 이야기를 해보겠습니다.
데이터란 자료의 모음이라고 보면 좋을 것 같습니다. 이 자료들을 특정한 조건으로 추려서 재 정리 한다면 이것은 정보(information)가 됩니다. 정보들은 또 특정한 목표를 가지고 의미를 부여할 수 있습니다. 의미있는 정보들은 지식(knowledge)으로써 고민하고 행동할 수 있는 조건 혹은 수단이 될 수 있습니다. 지식과 경험등을 모아 어떤 선택을하고 노하우가 쌓여 지혜(wisdom)가 되면 의사결정에 큰 영향력을 발휘할 수 있게 됩니다.
데이터 관리
위에서 설명한 대로 데이터가 중요하기 때문에 데이터는 사업의 연속성을 위해선 관리가 잘 되어야 합니다. 우리가 무서워하는 개인정보유출(벌써 다 털린것 같지만)은 사실 이 데이터가 해커에게 도난(복제) 당했다고 보시면 됩니다. 보안을 위한 내용은 이 글에서 다루지는 않을 것이지만 아래 정리한 내용에 더해 프로그래밍 적으로 혹은 시스템 설계적으로 보안에 신경을 써야 더 안전한 관리가 된다는 사실을 잊지 않으시길 바랍니다.
간단히 살펴 본다면 프로그래밍적으론 시큐어(secure)코딩이라는 것에 관심을 가져보시길 바라며, 인젝션 방어 등에 대해 알아 두시면 좋을 것 같습니다.
만약 시스템 설계를 할 때 크게 아래의 3 tier 구조로 설계한다면 web server : Apache, Nginx WAS(Web Application Server) : JSP(spring), Django, NodeJS, PHP DB
DB 서버는 전세계에 열어놓으면 안됩니다. 인바운드와 아웃바운드를 생각해서 DB서버 자신에게 접근해도 되는 곳에만 설정해야 합니다. 실제 서비스는 WAS에만 열어주어 해당 WAS를 통해서만 접근이 가능하도록 해야합니다.
SSH 키페어 방식으로 개발 서버(jump host)만 열어놓고 개발서버에서 각 웹서버, WAS, DB서버에 접근하도록만 열어놓고 사용자는 개발서버에 접속해서 개발을 진행하는 것이 가장 좋다고 합니다.(아직 제가 이대로 직접 설계해서 만들어 본적은 없습니다.)
그리고 중요한 부분중 하나는 사업 연속성을 위해서 DB는 정기적으로 백업 을 해야합니다.
DBMS : DataBase Management System
이 용어에 대한 정의를 저는 우리가 자주 사용하는 엑셀프로그램을 기본 컨셉으로 잡고 있습니다. 데이터들을 효율적으로 활용할 수 있도록 분류하고 저장해 놓는 프로그램이라고 생각하시면 됩니다. 데이터를 어떤 DBMS(이하 디비 라는 단어를 사용하겠습니다)를 활용해 저장할지는 개발 설계과정에서 중요한 포인트 중 하나입니다. 설계하고 있는 서비스의 사용자 수, 저장되는 데이터의 종류와 갯수 등을 고려하여 신중히 선택해야 합니다. (지옥을 맛보고 싶지 않다면…)
디비는 크게 관계형인 것과 관계형이 아닌 것으로 구분할 수 있습니다.
RDBMS(관계형 데이터베이스)는 전통적으로 많이 사용하던 디비 로 데이터들의 관계를 중요시하여 설계한 후 관리하는 방식입니다. 주로 SQL을 활용하여 데이터를 읽고 쓰고 등의 작업을 처리 합니다. 예) MySQL, Oracle, MS-SQL, PostgreSQL, SQLite 참고로 SQL[에스큐엘, 시퀄]은 이라고 읽으며 Structured Query Language의 줄임말 입니다. SQL에 대해선 아래에 좀 더 자세히 다루겠습니다.
관계형이 아닌것 : NoSQL ( Not only SQL )이라고 하며 보통 key-value방식을 이용하여 대용량의 데이터를 다루기 위해 고안된 데이터베이스 방식입니다. 예) MongoDB, Amazon DynamoDB, Redis 등등 종류가 많습니다. 각각의 장점이 뚜렷하기 때문에 필요한 것을 잘 찾아서 사용해야 합니다.
물론 대용량의 데이터를 위해 무조건 NoSQL을 사용해야 하는 것은 아닙니다. 데이터간의 관계 및 데이터가 저장될 스타일에 따라 다르며 NoSQL이 상대적으로 런닝커브가 낮지만 관계형 디비에서의 사용되는 트랜잭션이란 기능은 돈이 오가는 거래에서 장점이 되기 때문에 어떤 디비가 좋다라는 식의 접근 보다는 어떤 서비스를 위해 어떤 디비를 활용해서 효율적으로 관리할 것인가를 고려해보는 것이 중요합니다.
요즘엔 ORM ( Object Relational Mapping )이라는 기술(방식)이 등장하여 관계형 디비의 러닝커브를 높게 만드는 SQL사용을 하지 않는 방식(안에서 자동으로 처리해줌)이 발전하여 쉽게 디비를 사용할 수 있습니다. 하지만 편한만큼 마음대로 커스텀하기가 어려워 성능에 문제가 생길 수 있다는 단점이 있습니다. (개인 사업에서 디비가 성능상 문제가 있을 정도가 되면 사용자와 데이터 양이 많아진 것이므로 돈을 많이 벌었을거고 데이터베이스 관리자를 두면 된다 라는 Honux의 조언이 있었습니다 ㅎㅎㅎ 그리고 어렵다는건 불가능한게 아니라 노오오오력을 하면 가능할지도 모릅니다!)
DBMS 관련 용어 정리
테이블 ( Table ) : 데이터를 항목별로 구분해서 정리할 수 있도록 하는 틀 입니다. 엑셀화면(sheet)을 생각하면 이해하기 쉬울 것 같습니다.
칼럼 ( Column ) : 테이블 내에서 데이터가 쌓이는 항목. 데이터의 라벨이라고 볼 수 있을 것 같습니다.
primary key ( pk ) : 고유한 키. 테이블의 컬럼 중에 다른 데이터와 구분할 수 있는 데이터라고 할 수 있습니다. 한개 또는 중복의 컬럼으로 고유한 key를 만들어 다른 데이터와 구분할 수 있도록 하는 건데 예를 들어 실생활에서 우리가사용하는 이름은 동명이인이 많으므로 pk값이 될 수 없습니다. 하지만 이름과 핸드폰번호를 묶는다면 고유한 한사람이 될 수 있는거죠. 하지만 더 쉽게 주민번호로 pk를 정하면 나만의 고유번호라 한개의 데이터로 원하는 데이터(특정 개인의 신상정보)를 찾을 수 있는거죠. 물론 주민번호같은 데이터는 요새 직접 다루지 않는것이 보안상 유리하고, 테이블에 데이터가 생성될 때 자동으로 숫자를 올려가며 데이터를 넣어주는 방식을 많이 사용하고 있습니다. 그럴 경우 보통 테이블의 id값이라고 사용합니다.
foreign key ( fk ) : 참조 키. 다른 테이블의 데이터를 참조하여 데이터의 연관성을 부여합니다. 보통 다른 테이블의 pk값을 이용하여 해당 테이블에 참조를 하며, 그 참조된 데이터가 pk가 될 수도 있습니다.
ERD ( Entity Relationship Diagram ) : 테이블과 컬럼, 그리고 키들의 관계를 사람이 알아보기 쉽게 그림으로 표현한 것입니다.
SQL ( Structured Query Language )
SQL은 디비를 다루기 위한 언어라고 할 수 있습니다.
크게 세가지로 구분하며 아래와 같은 명령어를 시작으로 사용합니다.
데이터 정의 언어(DDL:data definition language) - Create, Alter, Drop등의 명령어가 있습니다. 보통 서비스의 설계나 수정사항이 있을 경우 전체적인 테이블 구조와 관계등을 설정할 때 사용합니다.
데이터 조작 언어(DML:data manipulation language) - Select, Insert, Delete, Update 등이 있습니다. 개발자들이 프로그램을 작성할 때 사용하게될 언어로 실제 데이터의 삽입, 삭제, 수정, 조회 등의 작업을 위해 사용합니다.
데이터 제어 언어(DCL:data control language)- Grant, Revoke, Commit, Rollback 등이 있습니다. 이미 조작된 데이터의 상태를 결정하는 명령어로 되돌리거나 전체 서버에 적용시키는 등의 제어를 가능하게 합니다.
CRUD
( Create / Read || Retrieve / Update / Delete )
위에서 설명한 데이터 조작언어(DML)을 흔히 CRUD라고 합니다. CRUD는 읽고 쓰고 수정하고 삭제하는 등 개발자들이 가장 많이 사용하고 잘 알아둬야하는 명령어 입니다.
자바를 사용사면서 개념정리가 잘 되지 않았던 부분들을 정리하는 목적에서 글을 씁니다. 따라서 글에는 오타 및 오류가 있을 수 있으며, 혹시 이 글을 읽는 다른 사람들 그리고 저를 위해 틀린 부분이나 추가되어야할 부분이 있다면 주저하지 말고 알려주시기 바랍니다 ^^
예외 처리의 이유
일반적으로 프로그래밍, 즉 코딩을 할때는 정상적이고 이상적인 시나리오를 예상하며 진행을 합니다. 모든게 이상직이면 얼마나 좋을까요ㅠ 바로 여기서 부터 문제는 시작됩니다. 실제 상황에선 수 많은 예외상황이 발생하기 때문입니다. 개발을 하다보면 도대체 어떻게 이런식으로 접근하는거지? 라는 의문을 가지면서 특이한 케이스들을 맞이하게 됩니다. 이러한 상황을 만나다보면 프로그램이 오류를 발생시켜 프로그램이 종료되는 불상사가 생길 수 있습니다. 따라서 원활한 서비스를 운영하기 위해서는 예외처리(Exception Handling)을 통해 프로그램이 갑자기 원하지 않는 순간에 종료하지 않도록 처리해주어야 합니다.
예외의 종류
자바에서는 예외를 클래스로 관리합니다. JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해줍니다.
이 예외 클래스들은 크게 두가지로 나눌 수 있습니다.
바로 “컴파일 타임 예외”와 “런타임(Runtime) 예외” 입니다.
이름에서 알 수 있는 느낌대로 첫째는 소스를 작성하고 컴파일을 할 때 예외 처리코드가 필요한지 JVM에서 검사해주는 예외이고, 둘째는 컴파일 시에 따로 예외처리 코드 검사를 하지 않는 예외 입니다.
공통점
두 종류의 예외는 공통점이 있습니다. 모두 예외처리를 하지 않는다면 프로그램이 에러와 함께 종료된다는 점 입니다.
한마디로 모든 예외를 대할때 예외처리는 필수 라고 기억해야 합니다.
차이점
위에서 이름에서 오는 느낌의 차이를 언급 했지만 코드를 작성할때 알아둬야하는 차이점도 있습니다.
먼저 컴파일 타임 예외와 런타임 예외는 자바에서 클래스로 관리한다는 개념을 다시 짚고 넘어가야 합니다.
각 에러 클래스들은 상속을 통해 구현하는데, 상속의 최종 보스(부모)는 바로 Exception이라는 클래스(java.lang.Exception) 입니다. 이 공톰점이 바로 예외처리를 하지 않으면 프로그램이 예상치 못하게 종료되는 원인이라고 할 수 있습니다.
중요한 차이점은 그림의 오른쪽 아래쪽에 Exception에서 나눠지는 두 줄기로 확인 할 수 있습니다. Exception클래스를 직접적으로 상속하느냐(그림에서 Other Exceptions라고 생각하면됩니다.), 아니면 RuntimeException이라는 클래스를 통해 상속을 구현하느냐에 있습니다(그림에 없는 개념으로 RuntimeException아래에 가지를 뻗어내린다고 생각하면 됩니다.).
이 글에선 Exception클래스를 벗어난(Errors, Throwable 등) 이야기는 다루지 않겠습니다. 사실 제가 아직 개념이 덜 정리되었습니다. (추후에 이 글을 통해 업데이트를 하거나 다른 글을 통해 추가하도록 하겠습니다.)
덧붙여 말하면 RuntimeException 역시 Exception을 상속받지만, JVM이 각 예외클래스를 바라볼 때 RuntimeException을 상속받았는지 여부를 보고 판단하여 구분하는 것 입니다.
RuntimeException
런타임 예외는 자바 컴파일러가 체크를 하지 않기 때문에 개발자의 경험과 지식에 따라 처리하는 커버리지에 차이가 생깁니다. 따라서 자주 발생되는 런타임 예외는 어떤 오류 메시지가 출력되는지 잘 알아둘 필요가 있습니다.
NullPointerException 가장 빈번하게 발생하는 런타임 예외입니다. 객체 참조가 없는 상태, 즉 null값을 갖는 참조 변수로 객체 접근 연산자인 dot(.)을 사용했을 때 발생합니다.
ArrayIndexOutOfBoundsException 배열에서 인덱스 범위를 초과하여 사용할 경우 발생합니다. 위 예외를 발생시키지 않으려면 배열을 다룰때 배열의 길이와 인덱스를 항상 고려하여 코딩하는 습관을 들여야 합니다.
NumberFormatException 문자열로 되어 있는 데이터를 숫자로 변경할때 발생합니다. 보통 많이 쓰이는
위의 메소드를 호출할때 숫자로 변환 될 수 없는 문자가 포함되어 있을 때 예외가 발생합니다.
ClassCastException 타입변환(Casting)은 상위 클래스와 하위 클래스 간에 발생하고 구현 클래스와 인터페이스 간에도 발생합니다. 이러한 관계가 아닌데 억지로 타입 변환을 시도할 경우 예외가 발생합니다.
예외 처리
예외 처리를 하려면 try-catch-finally 구문을 알아야 합니다. 구문을 코드로 표현해보겠습니다.
1 2 3 4 5 6 7 8 9
try { // do something // 예외가 발생할만한 로직 수행 // 추가 수행 코드 } catch (예외클래스 e) { // 예외 처리 } finally { // 무조건 실행되는 코드 }
지금부터 설명이 길어질지도 모르니 심호흡한번 하세요 ㅎㅎ 일단 finally 문은 생략이 가능합니다. try-catch-finally에서 try-catch는 필수 구문이고, finally는 옵션입니다. finally는 주로 파일, 세션, DB연결등을 닫을때(close() 메서드활용) 유용하게 사용됩니다. 예외처리를 해도 무조건 실행되기때문에 정상적일때 처리해야되는 로직들을 수행할 수 있도록 해주는 옵션 구문입니다.
다시 중요한 try-catch로 돌아오면, try문에서 do something을 실행하다가 예외가 발생할만한 로직을 수행을 하면서 두가지 갈래길에 서게 됩니다. 첫번째 상황은 정상적으로 로직이 수행 됐을 경우입니다. 그렇다면 우리가 원하는대로 로직이 흘러가게되고, 그 경우 try의 모든 로직들이 수행된 후 catch구문을 뛰어넘고(무시하고) finally를 찾거나 없다면 그 밑의 로직으로 넘어갑니다. 두번째 상황은 예외사 발생한 경우입니다. 예외가 발생한 순간 예외 처리 규칙에 따라 catch가 해당 예외를 잡아(catch) 예외처리를 하게 됩니다. 이 때 try구문안에서 예외가 발생한 순간 아래 부분인 추가 수행 코드는 수행되지 않고(무시하고) 넘어가게 됩니다. 예외를 처리한후엔 finally구문을 찾아서 수행하고, 없다면 바로 해당 메소드를 종료하고(stack에서 제거) 호출한 부분으로 돌아가게 됩니다.
여기서 알아둬야할 부분은 catch문은 여러번 올 수 있다는 것입니다. 다중 catch문을 통해 여러 예외를 핸들링 할 수 있습니다.
1 2 3 4 5 6 7
try {
} catch (예외클래스1 e) {
} catch (예외클래스2 e) {
}
주의해야할 것은 아까 말했듯이 catch가 수행된 후에는 해당 메서드가 stack에서 사라지고 호출한 부분으로 돌아가기 때문에 여러개의 catch문을 작성하더도 한개의 catch문만 실행되며 위부터 순차적으로 검사를 하여 catch 합니다.
이쯤에서 예상하시는 분도 있겠지만, 이 이유로 예외 클래스의 범위가 아래에 있는 예외 클래스의 범위보다 넓다면(상속구조에서 부모쪽에 있는 클래스가 먼저 catch를 한다면) 뒤에 오는 범위가 작은 클래스에게는 기회가 오지 않고, 개발자나 사용자들이 중요하고 자세한 정보를 얻기가 힘들어 집니다. 따라서 상속구조상 하위에 속하는(범위가 좁은) 클래스를 catch문에 먼저(위쪽에) 선언하는 것이 중요합니다.
Java 7에서 추가된 예외 처리
멀티 catch 하나의 catch블록에서 여러 개의 예외를 처리할 수 있는 기능이며 한개의 catch괄호()안에 동일하게 처리하고 싶은 예외를 파이프(|)로 연결하면 됩니다.
1 2 3 4 5 6 7
try { /* 예외1 또는 예외2 발생 */ } catch (예외클래스1 | 예외클래스2 e) { // 예외처리 }
자동 리소스 닫기 try-with-resources를 사용하면 예외 발생 여부와 상관없이 사용했던 리소스 객체(각종 입출력 스트림, 서버 소켓, 소켓, 각종 채널)의 close()메소드를 호출해서 안전하게 리소스를 닫아 줍니다. 먼저 자바6 이전까지 사용했던 코드를 이용하여 FileInputStream을 예로 들어보겠습니다.
프로그램을 개발하다 보면 자바 표준 API에서 제공하는 예외 클래스만으로는 다양한 종류의 예외를 표현할 수가 없습니다. 그때는 개발자가 직접 예외클래스를 정의해서 원하는 방식으로 예외를 처리할 수 있습니다.
실제 운영을 하다보면 사용자 정의 예외클래스와 자바 표준 예외 클래스를 적절하게 조합하여 사용하여야 빠르고 정확한 예외 대응을 할 수 있기에 매우 중요한 스킬이라고 할 수 있습니다.
사용자 정의 클래스는 통상 Exception으로 끝나는 클래스명을 이용하며, 원하는 방식에 맞게 Exception 혹은 RuntimeException을 상속하면 됩니다. 예외 클래스도 다른 클래스와 마찬가지로 내부엔 필드 생성자, 메소드 선언을 모두 포함할 수 있지만 대부분 생성자만을 포함합니다. 클래스에 선언한 생성자를 통해 예외를 발생시키며, 보통 매개 변수가 없는 기본 생성자와 예외 발생원인(예외 메시지)을 전달하기 위해 String 타입의 매개 변수를 갖는 생성자 두개를 선언하는 것이 일반적 입니다. 예)
1 2 3 4
public class XXXException extends [ Exception | RuntimeException ] { publicXXXException(){ } publicXXXException(String message){ super(message); } }
Tip
사용자 정의 예외 클래스와 표준 예외 클래스 혼용하기
1 2 3 4 5 6 7
publicvoidtestException()throws MyException { try { // do something } catch (NumberFormatException e) { thrownew MyException("예외를 설명하는 메시지", e); } }
장점은 개발자나 사용자가 예외를 확인할 수 있는 메시지를 담고 있고. 던져진(throw) 예외를 호출한 부분에서 처리하면서 e.printStackTrace()나 e.getMessage()등을 활용해 예외 상황을 파악하는 중요한 정보들을 파악할 수 있습니다.
비지니스 위험도가 있는 중요한 예외는 컴파일 타임 예외로 처리하기 잔액부족, 아이디/비밀번호 오류 등 미리 인지가 가능하고 에러 발생시 고객에 피해가 가거나 비지니스에 타격이 생길만한 로직은 RuntimeException을 피하고 컴파일타임 예외로 처리하여 경각심을 갖고 대비할 수 있도록 준비한다면 원활한 서비스를 운영하는데 도움이 될 것입니다.
마무리
긴 글 읽어 주셔서 고맙습니다. 혹시 오타나 오류가 있다면 저를 포함한 글을 읽는 모든 사람을 위해 언급해 주세요 ~
글 중간에도 언급을 했지만 예외처리는 많은 경험과 지식이 필요합니다. 귀찮거나 복잡해진다는 이유로 피하지 말고 다양한 상황에 대한 유연한 생각을 가지고 최대한 꼼꼼하게 예외처리를 한다면 개발 역량도 올리고 고객을 만족시키는 서비스 제공에 한발 더 나아갈 수 있다고 생각합니다.