2019년 12월 23일 월요일

[Python] Bar 차트 그리기.

matplotlib을 이용해 작성한 Bar 차트 그리기 코드.
데이터 목록에 대한 라벨과 값을 같이 표시해준다.

import numpy as np
import matplotlib.pyplot as plt

def draw_bar_chart(values, labels, subject, draw_mean=True, fig_size=(10, 6)):
    x = np.arange(len(values))
    y = values

    figure = plt.figure(figsize=fig_size)   
    barlist = plt.bar(x, y, 0.7, align='center')

    mean = np.mean(y)
    if draw_mean == True:
        plt.axhline(mean, color='coral', linestyle='dashed', linewidth=1)

    handles = []
    for index in np.arange(len(barlist)):
        if barlist[index].get_height() > mean:
            color = '#ec8482' # red like
        else:
            color = '#a4d8ee' # blue like
        barlist[index].set_color(color)
        handles.append(plt.Rectangle((0,0), 1, 1, color=color))

    plt.title(subject)
    plt.legend(handles, labels)
    plt.xticks(x, labels)

    for bar in barlist:
        height = bar.get_height()
        val = int(height)
        plt.text(bar.get_x() + bar.get_width() / 2.,
                 height + height*0.01,
                 val, ha='center', va='bottom')
    plt.show()

draw_bar_chart([1,2,4,6,7,7], ['v1','v2','v3','v4','v5','v6'], 'sample')

[펌] 데이터 분석으로 미래를 예측할 수 있을까

https://brunch.co.kr/@amangkim/35

아래는 개인적으로 추린 요약. 원문을 읽는게 당연히 좋다.

  "데이터를 다루는 사람은 많은 양의 데이터 수집을 통해 보다 정확한 미래를 예측할 수 있다고 믿는다. 하지만 데이터는 어찌됐던 과거의 산물이다. 데이터의 양이 많아진들 그 또한 과거의 것이기 때문에 미래를 직접 대변할 수는 없을 것이다. 많은 데이터 과학자들은 데이터를 이용해 미래를 예측하거나 영향력을 분석한다. 여기엔 큰 가정이 깔리는데 그 가정은 '과거의 사건들이 현재나 미래에도 재현된다.'라는 것이다. 모든 통계학의 예측 모델은 바로 이 재현성을 기반으로 한다. 그러나 미래는 재현되지 않는다. 쉽게 적으면 2017년 1월 1일은 1999년 1월 1일과 다른 것을 떠올리면 될 것이다. 비슷하게 보일 뿐 같은게 아니다. 통계를 통한 미래 예측은 과거를 기반으로 미래를 Simulation하는 것만이 가능할 뿐, 실질적인 미래를 예측할 수는 없을 것이다."

글쓴이는 예측과 패턴을 구분짓고 있다. 이 둘을 구분하는 기준은 시간의 영향력, 즉 재현성인데 시간의 영향력(시간에 따라 결과가 크게 달라진다면)이 크면 예측이 되고, 시간의 영향력이 없거나 작으면 패턴의 문제가 되는 것이다. 시간의 영향력이 작다는 것은 조건만 맞으면 같거나 아주 비슷한 결과가 재현 된다는 것을 뜻한다. 이건 충분히 가능하다는게 글쓴이의 주장이다. 즉, 데이터 분석의 목표로 잡아야 할 것은 미래의 예측이 아니라 과거 데이터로부터 패턴을 찾아내는 것이다. 한계점을 받아들이고 데이터를 기반으로 추측된 값이 갖는 의미와 속성을 파악하는 것은 틀림없이 유용한 도구가 된다.

무언가를 시도하기에 앞서 잊지 말아야 할 것은 데이터 과학의 기반이 되는 통계학, 확률론이 가지는 속성, 확률론의 모집합이 되는 수학이 갖는 속성을 되도록 바르게 파악하고 있어야 한다.

2019년 12월 22일 일요일

개발 분야와 관계없이 알아야 하는 기술 10가지

개발 분야와 관계없이 알아야 하는 기술 10가지 - 이기곤@수아랩

한빛 데브그라운드 주니어 2019년 발표 내용 정리.

1. 문자열 인코딩: 인코딩이란 컴퓨터가 문자를 이해할 수 있게 만든 규칙.
 - ASCII: ANSI에서 표준화한 7비트 부호체계. 영문 키보드로 입력할 수 있는 모든 기호들이 할당되어 있음. UTF-8과 호환, UTF-16과는 비호환.
 - EUC-KR: 완성형 한글 인코딩 방식 중 하나로 시작은 '가', 끝은 '힝'. 지원 글자 수는 2,350자로 현대에 쓰이는 한글 11,172자에 비해 부족. (Legacy, 결제 모듈 등에서 아직 쓰임.)
 - Unicode: 전 세계의 모든 문자를 다루도록 설계된 표준 문자 전산 처리 방식. Unicode 인코딩 방식엔 UTF-8, UTF-16, UTF-32가 있고, 일반적인 상황에선 UTF-8을 Unicode라 봐도 무방.
 - UTF-8: 사실상 표준으로 글자당 1~4 바이트를 쓰는 가변 길이 인코딩 방식. 1바이트 영역은 ASCII 코드와 하위 호환성을 갖음.
 - UTF-16: 2바이트 고정 인코딩 방식. 자바, 윈도우즈 API에서 쓰이는데 멀티바이트라고도 함. 호환성 목적으로 지금도 쓰임.
 - UTF-32: 4바이트 고정. 데이터 낭비가 심해서 사실상 쓰지 않지만 가변 길이를 고려하지 않아도 되는 장점 또한 존재해 프로그램 내부적으로 쓰이는 경우도 있음.

​2. Base64: 바이너리 데이터(이미지, 텍스트, 동영상)를 아스키 기반 문자열로 인코딩하는 방법. (Base64가 암호화는 아님.)
 - 문자 코드에 영향을 받지 않도록 공통 ASCII 영역의 문자만을 이용해 인코딩 함.
 - 64진법. 전자 메일이나 웹 등의 환경에서 바이너리 데이터를 전송하는데 쓰임. (RFC 1421, RFC 2045)
 - 바이너리 -> 텍스트 변환 간 일반적으로 33% 데이터 용량이 증가.

3. JSON: 구조화 텍스트 기반 데이터 규격. 정수, 실수, 텍스트를 규격화해서 실어 나르는 용도.
 - 장점: 범용적, 읽기 편함. 디버깅 용이. (JSON 자체가 JavaScript Object Notation인 만큼 JavaScript 언어와 궁합이 아주 좋다.)
 - 단점: 고용량, 처리 비용이 높음. (일반적인 사용 사례에선 무시해도 되는 수준이나 Latency가 중요한 게임, 금융 도메인에선 사용에 제약.)
 - JSON 규격 변경에서 오는 결함 가능성을 염두하고 사용해야 함.
 - Latency가 중요한 경우엔 Google Protocol Buffer 또는 Apache Thrift 사용이 권장됨.

​4. 다국어 처리: 프로그램 수정없이 여러 언어를 지원하는 기법.
 - 리소스 파일 방식, 언어 설정 방식, 프로그램 방식(하드코딩)으로 대응할 수 있음.
 - 일반적으론 Key:Value 기준으로 타깃 언어를 획득하는 방안.
 - Python엔 gettext 패키지, 안드로이드, C# 등의 언어는 프레임워크 레벨에서 지원됨. 표준은 i18N

​5. 날짜와 시간
 - 데이터를 주고 받는 상호간 타임존이 서로 다르면 문제가 발생함. 타임존 기준은 UTC, 한국은 UTC+9. 하나의 시스템은 하나의 타임존을 쓰도록 하는 것이 권장됨.
 - Apache Zookeeper 같은 분산 코디네이션 툴을 쓰면 특정 시스템의 타임존 변화를 감지할 수도 있음. 또는 주기적으로 상호간 타임존을 확인하고 맞추는 프로토콜을 반영하는 것도 고려할 수 있음.
 - 시간엔 단조 시간과 실제 시간(벽 시계 시간, wall time)이 있음.
 - 단조 시간? 운영체제나 CPU가 계산하는 시간으로 운영체제 시작 이후 종료까지 절대 바뀌지 않는 시간을 말함. 단조 시간은 컴퓨터마다 독립적.

​6. 정규표현식 (Regex): 주어진 문자열 속에서 특정 패턴을 찾고자 할 때 쓰는 기술.
 - 비밀번호 패턴에 숫자 1개, 영어 소문자 1개, 영어 대문자 1개 포함 조건 같은걸 적용한다면 정규 표현식으로 걸러낼 수 있음.
 - 정규표현식은 regex101.com과 같은 사이트에서 미리 검증해볼 수 있음.

​7. UUID: 범용 고유 식별자. 네트워크 상에서 서로 모르는 개체를 식별하기 위한 기술.
 - 4개의 하이픈과 32개의 16진수 문자로 구성. 하이픈을 빼면 저장하는데 16바이트가 필요함.
 - UUID v4는 중앙 관리 시스템에서 고유 ID를 할당받는 방식이 아니라 개발 주체가 스스로 식별자 이름을 짓는 방식임.
 - 중앙의 서버 없이 Object, 작업, 요청 등에 ID를 메기고 싶은 경우 UUID를 쓰면 된다.
 - 340,282,366,920,938,463,463,374,607,431,768,211,456개의 경우의 수를 갖기 때문에 사실상 중복은 없다고 인정됨.
 - UUID에도 충돌은 있을 수 있으므로 신뢰성이 중요한 시스템에선 UUID Pool(UUID 십만개, 백만개를 먼저 생성한 뒤 그 안에서만 쓰도록)을 고려해야 함.

​8. Random: 게임 규칙, 랜덤 박스, 암호화키, UUID 등을 만드는데 쓰임.
 - 쓰임에 따라 유사난수와 완전 난수를 구분해야 함. 우리가 쓰고 있는 대부분의 난수는 유사 난수임.
 - 유사난수는 난수를 흉내낸 난수로, SEED 값을 주면 SEED 값 기준으로 일련의 숫자를 만들어낸다. 완전한 난수에 비해 연산속도가 빠름.
 - 게임에서 유사난수 같은걸 쓰면 특정 시간대의 아이템 드랍률을 미리 알 수도 있으므로 문제가 된다.
 - 완전 난수는 암호학적으로 안전. 유사 난수에 비해 3~4배 느림. 노이즈를 이용해 난수를 만들어내므로 예측 불가. 인증키 생성, 게임 아이템 생성 등에 쓰인다.

​9. 해쉬함수: 임의의 값을 고정길이 값으로 변환하는 알고리즘.
 - 특정 해시 알고리즘은 입력값, 입력길이와 무관하게 항상 같은 길이의 문자열을 반환한다.
 - 해시 맵 같은데 쓰인다. 해시 충돌이 있긴 하지만 가능성은 매우 낮으며 접근 비용이 O(1)이므로 매력적.
 - 민감한 데이터의 변조를 막는데 쓸 수 있다. 암호를 해시화해서 저장하는데 보안 향상을 위해 Salt가 추가됨.
 - SHA-256 이상을 쓰는것이 안전하지만 MurmurHash의 경우 안전하진 않아도 성능이 매우 좋아 Redis같은 곳에서 쓰인다.

​10. HTTP(S): 웹의 기반 기술. 텍스트 기반의 통신.
 - HTTP의 주요 성질은 Stateless. 상대가 살아있는지 요청하기 전엔 알 수 없다.
 - HTTP는 기본적으로 1개의 요청당 1개의 소켓을 사용. 요청 전 연결하고 데이터를 주고받은 후 연결을 끊음.
 - Stateless 성질을 보완하기 위해 Cookie, Session 등을 쓴다. (또는 웹소켓, HTTP/2를 쓰면 연결 중단 없이 데이터 송수신 가능)
 - Header에 주요 정보가 담긴다. (User-Agent, Content-Type, Accept ...)
 - HTTPS = HTTP + TLS, HTTPS의 암호화 수준은 TLS 버전에 따른다. 서버의 경우 인증된 제3자가 발급한 인증서가 필요.
 - 분산 환경에선 스티키 세션(처음 연결된 서버와만 통신되게끔 하는 개념), CORS(서로 다른 도메인간 요청을 허용해 주는 것.)에 대해 알아둘 필요 있음.

2019년 12월 18일 수요일

Base 64 인코딩 (RFC 1421, RFC 2045)

https://tools.ietf.org/html/rfc2045#page-24

바이너리 데이터를 문자 코드에 영향 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 문자열로 바꾸는 인코딩 방식. 64진법으로, 이는 2의 제곱수들에 기반한 진법들 중에서 화면에 표시되는 ASCII 문자들을 써서 표현할 수 있는 가장 큰 진법이다. 다음 제곱수인 128진법에는 128개의 기호가 필요한데 화면에 표시되는 ASCII 문자들은 128개가 되지 않는다. 이러한 까닭으로 Base 64 인코딩은 전자 메일이나 웹 등의 환경에서 바이너리 데이터를 전송하는데 쓰인다.

일반적으로 Base 64 인코딩은 62개의 'A-Z, a-z, 0-9'를 쓰며 62번째엔 '+', 63번째엔 '/'를 쓴다. 그리고 패딩이나 문자열의 끝을 처리하기 위한 문자로 '='를 쓴다. 이렇게 했을 때 데이터 전송량이 약 33% 정도 늘어나는 단점이 있지만 딱히 대안이 없다.

ASCII로 인코딩해서 바로 전송하는게 더 낫지 않느냐는 의문이 생길 수 있는데 시스템 별로 ASCII를 처리하는 방식에 차이가 있고 ASCII는 여러 제어 문자를 포함하고 있기 때문에 이기종 간 데이터 교환으로부터 안전(적합)하지 않다.