wsl2 종료되지 않게 하기 – Prevent wsl2 from exiting

wsl2를 실행해두고 linux 서버로 쓰려는 목적으로 wsl2가 며칠 이내에 자동으로 종료되어서 여러가지 설청 방법을 찾아서 wsl2를 항상 켜두는 방법을 전에 올린 적이 있었습니다.

그런데 그 방법은 결과적으로 작동하지 않았습니다.

조금 오래 버티기는 하지만 wsl2를 실행하고 열어둔 “터미널(terminal)” 이나 “파워쉘(powershell)”까지 종료 시키면서 확실하게 종료되고 맙니다.

아마도 강제로 종료되도록 확실해게 처리한 것 같습니다. 그래서 C#으로 wsl2가 죽었는지 학인해서 되살리는 애플리케이션을 간단하게 돌려서 실행했더니 3주째 잘 작동하고 있습니다.

간단한 것이지만 소스는 github에 있으니 필요하면 참고하세요.

https://github.com/euriion/wsl-reviver

Supabase 사용자 추가 에러 – Failed to create user: API error happened while trying to communicate with the server.

Supabase는 실시간 처리를 지원하는 데이터 저장 솔루션인데 backend api 기능과 데이터베이스를 묶어놓은 솔루션입니다.

서비스를 서비스로 제공하는 Saas를 구독해서 쓰거나 자체 설치해서 쓸 수 있습니다. 설치형은 docker를 이용해서 설치하게 됩니다.

그런데 설치할 꼼꼼하게 하지 않으면 문제가 생기는 것을 알았습니다.

문제

Supabase를 docker로 Ubuntu에 설치한 후에 대시보드에 접속해서 사용자를 새로 추가하려고 하니 다음과 같은 에러가 발생했습니다.

Failed to create user: API error happened while trying to communicate with the server.

에러 메세지기 매우 불친절해서 오류를 찾는데 시간이 꽤 오래 걸렸는데요 API와 관련된 부분이 잘못 설치된 것인지 확인하고 재설치까지 여러 번 해봤지만 해결되지 않았습니다.

원인 발견

여러가지를 해보다가 발견한 원인은 supabase를 설치할 때 .env를 잘못 세팅한 것이었습니다.

바로 아래의 화면에서 사용자를 추가할 때 추가되지 않는 것인데 사실 사용자 추가 뿐만 아니라 기능 몇가지가 모두 작동하지 않고 있었습니다. 아래 화면은 사용자 추가가 성공한 모습입니다.

supabase의 레파지토리에 docker를 이용해서 설치할 때 사용하도록 .env.local이라는 파일을 제공하고 있고 실제 사용할 때는 .env로 파일 이름을 바꾸고 내용을 수정해서 사용해야 합니다.

파일내용입니다.

############
# Secrets
# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
############

POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
DASHBOARD_USERNAME=supabase
DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated
SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
VAULT_ENC_KEY=your-encryption-key-32-chars-min


############
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
############

이때 위의 내용을 아무렇게나 입력해서 고치면 안되고 JWT_SECRET, ANON_KEY, SERVICE_ROLE은 생성규칙이 있어 그에 맞게 생성된 것을 사용해야 합니다.

여기서 문제가 되는 것이 key를 생성하는 도구가 따로 있다는 것입니다.

생성하는 방법은 아래의 설치 가이드 페이지에 보면 생성하는 도구가 페이지 안에 붙어 있습니다. 페이지에서 버튼을 몇 번 눌러 사용할 값을 바꾼 후에 바뀌는 것들 중 한 세트를 골라서 .env에 넣으면 됩니다.

https://supabase.com/docs/guides/self-hosting/docker

위와 같은 화면입니다.

.env를 위의 페이지에서 생성한 값으로 바꾸고 나서 다음과 docker를 다운시킵니다.

docker compose down

그리고나서 컨테이너를 다시 실행하면 됩니다.

docker compose up -d

WSL2를 항상 켜두는 방법: 백그라운드 유지 문제 해결하기

문제 상황

WSL2(Windows Subsystem for Linux 2)를 PC나 Mini PC에서 리눅스 서버처럼 계속 실행해두고 싶었습니다. 하지만 시간이 지나면 자동으로 종료되어 서버로 사용할 수 없는 문제가 발생했습니다.

여러가지를 해봤지만 모두 실패했는데 성공한 방법을 공유합니다.

시도했던 해결책들

1. 백그라운드 프로세스 실행

WSL2는 기본적으로 백그라운드에서 실행 중인 프로세스가 없으면 자동으로 종료될 수 있습니다. 백그라운드 프로세스를 실행해 놓았지만 효과가 없었습니다.

2. 시스템 절전 모드 비활성화

Windows 시스템이 절전 모드나 하이버네이트로 전환되면 WSL2가 중단될 수 있습니다. 절전 모드를 사용하지 않도록 설정해 보았지만 역시 해결되지 않았습니다.

3. WSL 설정 문제 확인

특정 서비스(예: Redis) 실행 시 WSL이 중단되는 경우가 있다고 하여 확인했지만, 이런 문제는 없었습니다.

4. 리소스 과부하 체크

WSL2가 과도한 메모리나 CPU를 사용할 경우, Windows가 이를 강제로 종료할 수 있습니다. 예를 들어, vmmem 프로세스가 높은 리소스를 소모하는 경우가 있는데, 이런 경우 자동 종료될 수 있습니다. 하지만 이 문제도 아니었습니다.

5. 기본 쉘 설정 확인

기본 쉘 설정이 잘못되어 실행되지 않거나 종료되는 경우도 있습니다. 예를 들어, 삭제된 쉘(zsh 등)을 기본으로 설정한 경우 문제가 발생할 수 있지만, 이 문제도 아니었습니다.

해결 방법

여러 방법을 시도한 끝에 다음 명령어를 실행하면 WSL2가 백그라운드에서 계속 실행되는 것을 확인했습니다:

wsl --exec dbus-launch true

이 명령어는 WSL 프로세스를 활성 상태로 유지해줍니다. D-Bus 세션을 시작하고 이를 통해 WSL의 백그라운드 프로세스가 계속 실행되도록 합니다. 이렇게 해도 2주 정도 지나면 종료될 수 있습니다.

추가로 아래의 페이지에 가서 systemd 스크립트를 실행해 둡니다.

https://github.com/DamionGans/ubuntu-wsl2-systemd-script

그리고 인도우의 홈 디레토려에 .wslconfig 파일을 생성하고 아래의 내용을 넣습니다. 메모리 크기 같은 것은 적절히 원하는 값으로 변경하세요.

[wsl2]

# Limits VM memory to use no more than 4 GB, this can be set as whole numbers using GB or MB
memory=8GB
vmIdleTimeout=-1
#networkingMode=mirrored

# Sets the VM to use two virtual processors
processors=4

결론

WSL2를 리눅스 서버처럼 지속적으로 사용하려면 여러 설정이나 최적화가 필요할 수 있습니다. 그중에서도 wsl --exec dbus-launch true 명령어가 가장 효과적인 해결책이었습니다. 이 방법으로 WSL2를 지속적으로 실행하여 서버 용도로 안정적으로 사용할 수 있게 되었습니다.

Tauri: 가벼운 데스크탑 애플리케이션 프레임워크

1. Tauri란 무엇인가?

Tauri는 데스크탑 애플리케이션을 개발할 수 있는 가볍고 안전한 오픈 소스 프레임워크입니다. Tauri를 사용하면 웹 기술을 이용해 Windows, macOS, Linux에서 실행 가능한 네이티브 애플리케이션을 만들 수 있습니다. 주로 Rust와 **웹 기술(HTML, CSS, JavaScript)**을 결합하여 제작되며, 성능과 보안 측면에서 매우 강력한 특징을 갖고 있습니다.

2. 왜 Tauri인가?

Tauri는 Electron이나 다른 데스크탑 앱 프레임워크에 비해 매우 경량입니다. 기존의 Electron 앱은 크롬과 같은 브라우저 엔진을 내장하여 용량이 큰 경우가 많습니다. 하지만 Tauri는 시스템의 네이티브 웹뷰를 사용하기 때문에 앱의 크기가 훨씬 작습니다.

주요 장점:

  • 가벼움: 앱 크기가 매우 작고, 시스템 리소스를 적게 사용합니다.
  • 보안성: Tauri는 보안을 최우선으로 하며, 웹 기술을 기반으로 하면서도 로컬 파일 시스템 접근을 최소화합니다.
  • 다중 플랫폼 지원: Windows, macOS, Linux 모두에서 동일한 코드베이스로 빌드가 가능합니다.
  • Rust의 성능: Tauri는 백엔드에서 고성능 언어인 Rust를 활용하여 더 빠른 실행 속도를 제공합니다.

3. Tauri와 Electron 비교

TauriElectron
기술 스택Rust + 웹 기술Node.js + Chromium
애플리케이션 크기1~10MB (작음)50~100MB (큼)
리소스 사용량적음많음
보안높은 보안성상대적으로 낮음
성능Rust 기반으로 매우 빠름비교적 무거움

4. Tauri의 특징

  1. 작은 크기: Tauri로 만든 애플리케이션은 1MB에서 10MB 정도의 크기를 가집니다. 작은 애플리케이션 크기는 다운로드 시간과 설치 시간을 크게 줄여줍니다.
  2. Rust로 백엔드 작성: Rust의 고성능과 안전성을 활용할 수 있습니다. Rust는 메모리 안전성을 보장하며, 시스템 리소스를 효율적으로 사용합니다.
  3. 웹 개발자의 쉬운 접근성: 이미 HTML, CSS, JavaScript를 알고 있는 웹 개발자라면 Tauri를 이용해 데스크탑 애플리케이션을 빠르게 개발할 수 있습니다.
  4. 보안성 강화: Tauri는 애플리케이션과 로컬 시스템 간의 상호작용을 엄격히 제한합니다. 보안에 민감한 앱 개발 시 매우 유용합니다.

5. Tauri로 개발을 시작하려면?

Tauri를 시작하려면 아래의 개발 환경이 필요합니다:

  • Rust 설치: Tauri는 Rust를 백엔드로 사용하므로, 먼저 Rust를 설치해야 합니다.
  • Node.js 및 패키지 관리자 설치: JavaScript 및 패키지 관리를 위해 Node.js와 npm/yarn을 설치합니다.
  • Tauri CLI 설치: 프로젝트를 생성하고 빌드하는 데 필요한 CLI 도구입니다.
bash코드 복사# Rust 설치
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Node.js 및 패키지 관리자 설치 (Node.js 웹사이트에서 다운로드)
npm install -g tauri-cli

6. 결론

Tauri는 기존의 데스크탑 애플리케이션 개발 프레임워크보다 경량화된 솔루션을 제공합니다. Rust의 성능을 바탕으로 웹 기술과 결합하여 데스크탑 앱을 쉽게 개발할 수 있고, 작은 앱 크기와 높은 보안성 덕분에 사용자 경험도 우수합니다. Electron이 제공하는 풍부한 기능이 필요하지 않거나, 더 가벼운 대안을 찾고 있다면 Tauri가 훌륭한 선택이 될 수 있습니다.

데이터 엔지니어와 데이터 사이언티스트의 차이

데이터 엔지니어(Data Engineer)와 데이터 사이언티스트(Data scientist, 데이터 과학자)에 대한 차이에 대한 포스트입니다.

GPT나 Claude에게 물어보면 잘 대답해 주겠지만 그냥 설명하기 쉽게 표로 만들어 봤습니다.

질문 항목데이터 엔지니어데이터 사이언티스트 (데이터 과학자)
무슨 일을 하는가?데이터 처리에 대한 일을 한다.데이터 분석과 활용에 대한 일을 한다.
한마디로 하는 일을 쉽게 설명하면?데이터 저정, 흐름, 이용에 대한 것을 관리한다.데이터의 분석, 재활용을 통해 부가가치 창출과 서비스 고도화를 한다.
일과 시간에 하는 일은?대부분의 시간을 데이터 플랫폼을 다루는데 쓴다.
S3, BigQuery, Hadoop/Hive/Spark
대부분의 시간을 데이터를 분석하고 모델을 만드는데 쓴다.
통계분석, ML/AI 모델링, 모델 성능 분석
주로 사용하는 도구는?개발툴 보다는 터미널, 관리툴 등을 주로 사용한다.개발툴 보다는 주피터노트북이나 모델링을 위한 스크립트 파일을 작성할 수 있는 편집기를 주로 쓴다.
데이터와 관련된 어떤 일을 하는 것인가?ETL과 같은 업무에 깊이 관여하며 데이터가 잘 전송되고 정합성 문제가 없는지 확인하는 것에 중점을 둔다.ETL 보다는 Feature Engineering이나 aggregation 더 깊이 관여하며 정합성 보다는 좋은 통계적 인사이트를 찾거나 모델을 만드는데 더 중점을 둔다.
포지션(일자리) 수요데이터 관련 인프라 유지가 필요한 회사에서만 포지션이 있다.데이터 분석, 데이터 과학을 서비스에 적용할 일이 있는 회사에만 필요
경력이 많아짐에 따라 발전 하는 것어느 정도 경력이 쌓이면 더 발전할 것은 없고 사용하는 솔루션의 종류가 운영 경험이 쌓인다.데이터로 부터 얻을 수 있는 인사이트에 통찰이 생기며 다양한 모델링의 종류와 경험이 쌓인다.
급여 수준일반적으로 개발자 보다 조금 높다일반적으로 개발자 보다 많이 높다

Nginx로 userid (쿠키 세션 ID) 자동 생성하기

세션ID, 쿠키ID

쿠키에서 넣어놓는 세션ID(사용자ID)를 속칭 쿠키ID라고 합니다.

웹사이트나 포털사이트에 비로그인 접속자들을 추적하기 위해서 사용합니다.

구글, 네이버, 온라인광고, 이커머스 등의 사이트에서 사용자의 행적을 추적할 때 가장 많이 사용합니다.

이 비식별 키를 기준으로 사람들의 행동을 쌓아놓은 로그데이터인 행적데이터(로그 데이터)가 빅데이터에서 말하는 대량 데이터의 핵심 중 하나입니다. 이 로그를 분석하면 인사이트가 나옵니다.

로그인하지 않는 경우에는 추천시스템도 이 데이터를 기본으로 만들며 세그멘테이션, 데이터 교환 같은 것도 다 이것을 기준으로 합니다.

생성 방법

예전에는 백엔드서버에서 생성을 해서 쿠키로 생성해주는 방식을 많이 썼지만 NginX에 userid라는 모듈이 있어서 이 일을 대신해주니 편리합니다. NginX 없이 바로 웹서비스를 하는 경우에는 구현이 필요합니다.

보통 랜덤값을 생성해서 16바이트 또는 32바이트 16진수값을 문자열로 바꿔서 넣습니다.

사용자의 IP나 특별한 정보를 넣기도합니다만 쓸모가 없어서 요즘은 잘 하지 않습니다.

userid on;
userid_name uid;
userid_domain example.com;
userid_path /;
userid_expires 365d;
userid_p3p 'policyref="/w3c/p3p.xml", CP="CUR ADM OUR NOR STA NID"';

만료기간은 기본 1년으로 되어 있지만 넉넉하게 5년쯤으로 넣어 놓으면 됩니다.

셀리니움 “Chrome이 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다” 없애기

Python

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service

options = Options()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

# user-agent를 일반적인 브라우저와 비슷하게 설정
options.add_argument('--disable-blink-features=AutomationControlled')

# 크롬 드라이버 경로 설정
service = Service(executable_path="path_to_chromedriver")

driver = webdriver.Chrome(service=service, options=options)

# 필요한 작업 수행
driver.get('https://www.example.com')

# 작업 종료 후 드라이버 종료
driver.quit()

Zulu JDK와 Jenkins 설치하기 – Ubuntu 24.04

Ubuntu 24.04에 Zulu JDK와 Jenkins를 설치하는 방법

Ubuntu 24.04에 Zulu JDK와 Jenkins를 설치하는 방법을 단계별로 설명드리겠습니다.

이 가이드에서는 먼저 Azul Zulu JDK를 설치한 후, Jenkins를 설치하는 절차를 다룹니다.

Jenkins는 Groovy 언어로 개발되었으므로 JDK가 필요합니다. Zulu JDK가 성능이 좋고 사용하기 편안하므로 무난하게 이걸 설치합니다. Jenkins는 가능한 최신 버전을 설치합니다.

1. Azul’s Public Key 등록

먼저, Azul의 공용 키를 등록합니다.

이를 위해 gnupg, ca-certificates, 및 curl을 설치한 후, 공용 키를 다운로드하고 시스템에 등록합니다.

sudo apt install gnupg ca-certificates curl
curl -s https://repos.azul.com/azul-repo.key | sudo gpg --dearmor -o /usr/share/keyrings/azul.gpg
echo "deb [signed-by=/usr/share/keyrings/azul.gpg] https://repos.azul.com/zulu/deb stable main" | sudo tee /etc/apt/sources.list.d/zulu.list

2. 사용 가능한 패키지에 대한 정보 업데이트

Azul Zulu 리포지토리를 설정한 후, 패키지 목록을 업데이트합니다.

sudo apt update

3. 필요한 Azul Zulu 패키지 설치

이제 설치하고자 하는 Zulu JDK 버전을 설치합니다. 예를 들어, Zulu 21 JDK를 설치하려면 아래 명령을 실행합니다.

sudo apt install zulu21-jdk -y

4. 자바 설치 버전 확인

설치가 완료되면, Java가 올바르게 설치되었는지 확인합니다.

java -version

예상 출력:

openjdk version "21.0.1" 2023-10-17 LTS
OpenJDK Runtime Environment Zulu21.30+15-CA (build 21.0.1+12-LTS)
OpenJDK 64-Bit Server VM Zulu21.30+15-CA (build 21.0.1+12-LTS, mixed mode, sharing)

Jenkins 설치

다음으로, Jenkins를 설치하는 방법을 안내드리겠습니다.

1. Jenkins의 Public Key 등록

먼저, Jenkins의 공용 키를 다운로드하여 시스템에 등록합니다.

sudo wget -O /usr/share/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key

2. Jenkins 리포지토리 추가

Jenkins 리포지토리를 추가합니다.

echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null

3. 패키지 목록 업데이트

패키지 목록을 업데이트합니다.

sudo apt-get update

4. Jenkins 설치

마지막으로, Jenkins를 설치합니다.

sudo apt-get install jenkins

이로써 Ubuntu 24.04에 Zulu ZDK와 Jenkins를 성공적으로 설치할 수 있습니다.

추가적인 설정이나 문제 해결이 필요하시면 공식 문서나 커뮤니티 포럼을 참고하시기 바랍니다.

Direct Preference Optimization (DPO)

DPO는 LLM에서 사용하는 튜닝 방법입니다.

GPT는 Pretrained 단계를 거쳐 Fine-tuning에서 RLHF라는 사람의 피드백에 의한 강화학습을 합니다.

PPO라는 것을 쓰는데요.

채점 모델을 만들어 채점모델이 모델이 생성한 텍스트를 채점하게 해서 그걸 다시 학습으로 돌려서 모델의 성능을 개선하는 방법입니다.

대표적으로 ChatGPT가 이 방법을 사용합니다.

DPO는 인간의 피드백없이 그냥 선호하는 데이터로 모델을 튜닝하는 방법입니다.

일반 fine-tuning하고 뭐가 따른지가 궁금할텐데 일반 fine-tuning은 인간의 피드팩 데이터를 넣지 않을 수도 있고 넣을 수도 있만 DPO는 인간의 피드백을 그 자체로 학습에 사용하는 방법입니다.

대표적으로 Llama3가 이 방법을 사용합니다.

데이터브릭스 데이터 인텔리전스 데이 서울 2024

제목이 좀 기네요.

데이터브릭스 이벤트행사에 다녀왔습니다. 이 이벤트는 컨퍼런스 형식입니다.
모든 세션을 다 듣지 못했지만 들은 세션의 내용을 가지고 종합하면

좋았던 점

  1. 궁금한 것에 대해서 뭘 하고 있는지 어떻게 대응하고 있는지 잘 설명해줬다.
  2. 내용이 알찼고 섬세했다.
  3. 사용자의 LLM의 생성과 튜닝에 대해 준비가 어떻게 되어 있는지 잘 알려주고 있다.
  4. LLM을 응용한 여러가지 편의 기능과 최적화 기능 들은 인상적이었다.

아쉬운 점

  1. 설명할 내용이 많았는지 스피커들의 스피치속도가 빨라서 정식 없었다.
  2. 성공사례 발표가 많지 않았고 와닿지 않았다. 이건 다른 컨퍼런스도 마찬가지이지만 이게 아쉽네요.
  3. 협찬업체가 적어서 경품 부쓰가 적었다.

이렇습니다.

느낌은
무료 컨퍼런스임에도 매우 알차고 괜찮어서 만족스러웠습니다.
데이터브릭스 직원분들 능력이 좋은 것 같습니다.
사람이 많아서 많이 정신 없고 피곤했습니다. 인기 실감

Iphone에서 MLX로 Llama3 로딩 성공

iPhone에서 Llama3 8B 모델을 구동시키는데 성공했다는 뉴스가 나오자마자 인터넷 곳곳에서 따라하기에 성공사례가 연달아 나오고 있습니다.

정리하자면

애플 실리콘은 애플이 독자적으로 만든 반도체입니다. 그래서 인텔, AMD의 프로세서와 Nvidia GPU용으로 만들어진 모델이 그냥 작동하지 않습니다. Llama3도 마찬가지입니다. 돌아간다고 하더라도 효율이 문제인데 그래서 애플은 애플 실리콘에서 작동하는 자체 고속행렬연산 프레임워크인 MLX라는 것을 만들었습니다.

Llama3를 애플의 아이폰, 아이패드에서 돌리려면 MLX에서 돌도록 해야 제대로 되는데 그걸 매우 쉽게 했다는 것입니다.

아이폰 다음 모델에는 거의 온디비이스 AI 탑재될 것이 분명합니다.

온디바이스AI는 디바이스내에서 외부 통신없이 자체 능력만으로도 AI 프로세싱을 처리할 수 있는 것을 말합니다.

세상이 바뀌는 순간이 매우 빠르게 오고 있다는 느낌이 듭니다.

다음은 Llama3 8B를 iPhone 15 Pro Max에 설치하는 방법입니다. 편의상 영문 그대로 올립니다.

UPDATE: Successfully ran Llama3 8B Instruct on iPhone 15 Pro Max

Steps:

1. Install LLM Farm

2. Download Llama3 8B Instruct GGUF from Huggingface

3. Import & Run the model in LLM Farm

LLM Farm: https://llmfarm.site

Model File: https://huggingface.co/FaradayDotDev/llama-3-8b-Instruct-GGUF… Detailed steps coming soon!

Llama3의 성능 비교표

스펙과 성능에 대한 비교표입니다.

전반적으로 GPT-4가 가장 성능은 뛰어난 것으로 평가 받고 있습니다.
비용효율과 사용성 측면을 고려하면 성능을 조금 포기하고 모델의 크기와 같은 하드웨어적 특징을 고민해야 하기때문에 용도에 맞는 것을 선택해야 하겠습니다.

아무리 GPT가 성능이 좋아도 오픈소스경량 LLM인 Llama3의 매력을 무시하기는 어려울 것 같습니다.

LLM AI의 할루시네이션을 극복하려면?

할루시네이션은 언어 AI 모델(LLM)이 사실이 아닌 엉뚱한 소리를 사실 처럼 확증적으로 말하는 것을 말합니다.

할루시네이션(Hallucination)은 거짓말과는 다른데 거짓말은 의도적으로 진실을 말하지 않고 다르게 말하는 것인지만 AI는 진실과 거짓을 구별하지 못하고 의식이 없기 때문에 의도라는 것 자체도 없습니다.

그래서 틀린 사실도 매우 당연하다는 듯이 사실처럼 생성하기도 합니다. 그런데 AI가 생성한 텍스트가 진실인지 아닌지 알아차릴 수 있는 지식이 없다면 AI의 거짓을 착각해서 믿게 됩니다.

LLM은 할루시네이션 극복을 하기 힘들다

LLM 의 구조적인 특징으로 인해 할루시네이션은 AI모델 자체로는 완벽하게 극복이 안됩니다. 나중에 개선된 모델이나 다른 방법이 나온다면 가능하겠지만 지금은 아닙니다.

LLM의 작동방식은 확률적으로 입력한 단어의 다음 단어가 나올 것을 예측하고 그것을 매우 긴 단어의 연결에 대해 연속적으로 행하는 모델이기 때문입니다. 깊은 고찰이나 인과적 사실 검증, 사실 의심 같은 인간의 고급 사고 능력이 LLM에게 없기때문입니다.
그리고 인간도 할루시네이션이 있습니다. 잘못 알고 있는 것을 잘 알고 있다고 착각하고 우기는 것 말입니다. 하지만 인간은 자신이 틀렸을지도 모른다는 의심 또한 하기 때문에 현명한 사람들은 할루시네이션이 거의 없습니다.

학습량을 마구 늘리면 할루시네이션이 극복되지만 얼마까지 늘려야 눈치채지 못할 만큼 줄어드는지는 알 수 없습니다.

RAG (Retrieval Augmented Generation)

현재 LLM의 할루시네이션을 극복하는 거의 유일한 방법은 RAG (Retrieval Augmented Generation)을 사용하는 것입니다.

RAG는 AI가 대답할 때 질문과 관련이 있는 자료를 찾아서 참고해서 대답하게 만드는 방법입니다.

간단하게 말하면 AI가 대답하기 전에 벡터데이터베이스를 뒤져서 자료를 찾은 다음에 대답할 때 참고하도록 합니다. 당연히 벡터DB에는 사실만 저장되어 있어야 합니다.

RAG는 AI모델에 검색 엔진을 결합한 것

RAG에서 사용하는 DB또는 검색엔진 꼭 벡터 기반일 필요는 없습니다. 텍스트기반의 검색엔진인 엘라스틱 등을 사용해도 되고 DB를 사용해도 됩니다. 벡터 기반을 사용하는 이유는 벡터기반이 렉시컬 기반이 아닌 컨텍스트 기반으로 매치가 가능하기 때문입니다. 전통적인 검색엔진이나 DB는 단어들이 얼마나 일치하는지를 찾는 방법으로 쓰지만 벡터 기반은 의미가 비슷한지를 확인하는 구조로 되어 있습니다.

ASI모델을 사용할 때 RAG로 해결해야 하는 문제는 프롬프트와 관련이 있는 또는 챗봇의 경우 사용자가 질의한 것가 관련이 있는 것만 잘 추출해서 지시어로 넣어주어야 한다는 것입니다.
잘못된 검색 결과는 의미가 일치하지 않는 콘텐츠를 지시어로 넣어주면 할루시네이션이 생기거나 조금 엉성하고 엉뚱한 답을 하게 됩니다.

RAG가 정말 할루시네이션을 해결 해주는가?

다른 구조의 모델이 나오거나 파인튜닝을 엄청나게 많이 하지 않으면 RAG외에는 할루시네이션을 없애는 방법은 없습니다.

RAG를 위해서 필요한 것

  • 벡터검색엔진
  • 벡터검색엔진에 넣을 콘텐츠
  • RAG가 적용되어 빌드된 모델
  • 좋은 청킹 방법

여기서 가장 중요한 것은 2번입니다. RAG가 적용된 모델은 없어도 지시어로 충분히 해결할 수 있지만 있다면 더 매끄러운 결과를 보여줍니다.

청킹은 매우 중요한 기술인데 콘텐츠를 어떻게 잘라서 검색엔진에 추가할지에 대한 방법입니다. RAG에서 가장 중요한 노하우라고 할 수 있습니다.

좋은 방법은 잘 알려지지 않고 각 기업의 내부에서만 사용되고 있습니다. OpenAI도 RAG를 지원하지만 어떤 방법으로 청킹을 하는지에 대해서는 오픈하고 있지 않습니다.

RAG의 미래는?

AI모델을 실시간으로 빌드할 수 있는 방법은 없습니다. 모델을 만드는데 계산양이 매우 많기 때문입니다. 최신 지식을 인간처럼 곧바로 업데이트하지 못합니다.

유일한 방법은 어디선가 사실을 가져와서 모델내에 실시간으로 넣어주는 방법뿐입니다.

그래서 당분간은 RAG가 중요하게 쓰일 수 밖에 없습니다.

Llama3 발표

메타(Meta, 페이스북)의 LLaMa3 가 공개되었습니다.

앤드류 응 교수는 출시되지 마자 다음과 같은 멘트를 했습니다.
Meta released Llama 3 on my birthday! 🎂 Best present ever, thanks Meta! 😀

생일인데 Llama3이 발되었다고 좋은 선물이라고 하는데, 조금 오버입니다만 오버를 할 정도로 대단한 뉴스라는 것을 알 수 있습니다.

다른 많은 엔지니어들도 코멘트를 남겼으며 벌써 테스트를 해본 사람까지 있었습니다.

현재까지의 평가는 작은 사이즈에 비해 기존 모델과 비슷한 품질을 보여줘서 상당히 고무적이라는 평가입니다.
특히 Llama3의 가장 작은 모델은 8B모델은 LLama2의 7OB모델보다 MMLU 점수가 더 높았습니다.

MMLU는 언어모델의 지식 범위와 깊이를 측정하는 기준입니다.

LLama3에 대한 간단한 요약입니다.

  1. 24000개 H100 GPU가 붙은 클러스터 2개를 이용해서 모델 빌드
  2. 기존과 구조는 바꾼것 없이 데이터만 더 넣어서 성능 개선
  3. 제공 모델 크기는 8B, 70B, 400B+ (400B+은 아직 학습 중)
  4. 동급에 가장 리더보드 스코어가 높음
  5. 학습량 15T 토큰량. 5% 정도의 30개국어. 구글의 전세계 색인 문서의 1/4 수준
  6. 인스트럭션 러닝에도 많은 투자가 있었음. 즉 지시에 잘 따르고 말 잘듣게 학습시킴
  7. Azure에서 API, 웹페이지에서 모델 다운로드 가능
  8. 한국어 능력은 LLaMA2에 비해 크게 나아지지 않음. 다국어 학습량이 매우 부족해서 추가 필요
  9. 튜닝 후 배포할 땐 llama3- 라고 꼭 적어야함

아직 한국어는 좋지 않지만 조만간 튜닝이 된 파생 모델이 쏟아져 나올 것입니다.

이제 LLM은 ChatGPT가 출시된 첫번째 격동기에서 두번째 격동기에 접어들었습니다.

MMLU – 대규모 멀티태스크 언어 이해력 평가

MMLU: 대규모 멀티태스크 언어 이해력 평가

https://paperswithcode.com/sota/multi-task-language-understanding-on-mmlu

인공지능의 평가 및 비교를 볼 때 MMLU라는 지표를 자주 보게 됩니다.

MMLU(Massive Multitask Language Understanding)는 인공지능 모델의 지식 습득 능력을 종합적으로 평가하기 위한 벤치마크 중 하나입니다. 이 평가는 인공지능이 어느 정도까지 다양한 지식 영역을 이해하고 있는지를 측정하기 위해 고안되었습니다.

즉, 인공지능이 얼마나 다양한 지식을 가지고 있는지 평가하는 지표입니다.

MMLU의 특징

  • 다양한 주제 범위: MMLU는 STEM(과학, 기술, 공학, 수학), 인문학, 사회과학 등 약 57가지의 다양한 주제에 대한 이해를 평가합니다.
  • 다지선다 형식의 문제: 평가는 주로 다지선다 형식의 문제를 사용하여, 모델이 주어진 정보를 바탕으로 가장 적절한 답을 선택하도록 요구합니다.
  • zero-shot 및 few-shot 학습 환경: 이 벤치마크는 특히 모델이 사전에 해당 주제에 대한 특정한 학습 없이도 얼마나 잘 수행할 수 있는지(zero-shot), 또는 매우 제한된 데이터로 학습한 후의 성능(few-shot)을 평가합니다.

현재 성과와 리더보드

최신 인공지능 모델들의 성능은 Papers with Code 웹사이트의 MMLU 벤치마크 섹션에서 확인할 수 있습니다. 현재 GPT-4가 86.4%의 높은 정확도로 최고 성능을 기록하고 있습니다.

자료 및 리소스

  • 공식 GitHub: MMLU의 구현과 관련된 자세한 정보, 데이터셋 접근 및 사용 방법 등은 GitHub 페이지에서 확인할 수 있습니다. 이 페이지에는 또한 연구자들이 자신의 모델을 벤치마크에 적용해 볼 수 있는 지침과 도구들이 제공됩니다.

MMLU의 중요성

MMLU는 단순히 특정한 지식 영역에서의 모델 성능을 측정하는 것을 넘어, AI 모델이 얼마나 광범위하고 다양한 주제를 이해하고 있는지를 평가함으로써, 인공지능 기술의 종합적인 이해력과 다재다능성을 테스트합니다.

요약하면

MMLU는 현재 AGI를 만들어가는데 중요한 평가지표입니다.

OpenAI Assistant API v2 달라진점

OpenAI Assistant API는 openapi에서 모델을 활용해서 개발하게 하는 API인데 2023 말에 Beta V1을 발표했습니다.

하지만 몇가지 단점과 한계, 버그가 있었는데 새 버전 2가 발표되었습니다.

간략한 요약은 다음과 같습니다.

2024년 4월 발표. OpenAI Assistants API의 기본 버전에 새로운 기능과 개선 사항을 넣어 OpenAI-Beta: assistants=v2 릴리즈로 만듦

  • 파일 검색 도구 개선: ‘file_search’ 도구는 이전보다 500배 많은 최대 10,000개 파일을 처리할 수 있습니다. 이 도구는 검색 속도가 빠르고, 멀티 스레드 검색을 통한 병렬 쿼리를 지원하며, 향상된 재정렬 및 쿼리 재작성 기능을 제공합니다. 기능 개선 및 신규 지원
  • 벡터 스토어 객체 도입: 파일이 벡터 스토어에 추가되면 자동으로 파싱, 청킹, 임베딩되어 검색 준비가 완료됩니다. 벡터 스토어는 여러 보조기와 스레드에 걸쳐 사용할 수 있어 파일 관리와 결제가 간소화됩니다. 신규 지원
  • 토큰 사용 최대치 제어: 실행할 때 사용하는 최대 토큰 수를 제어할 수 있어 토큰 사용 비용을 관리할 수 있습니다. 또한, 각 실행에서 사용되는 이전/최근 메시지의 수에 대한 제한을 설정할 수 있습니다. 신규 지원
  • 도구 선택 매개변수 지원: 특정 실행에서 특정 도구(예: file_search, code_interpreter 등)의 사용을 강제할 수 있는 ‘tool_choice’ 매개변수를 추가했습니다. 신규 지원
  • 역할이 보조인 메시지 생성 가능: Threads에서 사용자 정의 대화 이력을 생성할 수 있습니다.
  • 보조 및 실행 객체의 모델 구성 매개변수 지원: 인기 있는 모델 구성 매개변수(온도, 응답 형식(JSON 모드), top_p 등)를 지원합니다. 신규 지원
  • 미세 조정 모델 사용 가능: 현재는 gpt-3.5-turbo-0125의 미세 조정 버전만 지원됩니다. 신규 지원
  • 스트리밍 지원: Assistants API가 이제 스트리밍을 지원합니다. 신규 지원
  • 스트리밍 및 폴링 도우미 추가: Node 및 Python SDK에 여러 스트리밍 및 폴링 도우미를 추가했습니다. 신규 지원
  • 마이그레이션 가이드 제공: 최신 버전의 Assistants API로 도구 사용을 마이그레이션하는 방법에 대해 자세히 알아볼 수 있습니다. 신규 지원

데이터 사이언스의 스킬 범위

데이터 사이언스에 대한 좋은 도표가 있어 공유합니다.

그림처럼 Python만 써야 하는 것은 아닙니다. Python은 데이터과학을 하는데 필요한 컴퓨터 기술을 통칭한다고 생각하면 됩니다.

데이터분석과 데이터과학을 구별하지 못할 때가 많은데 차이점은 도메인 날리지(업무 지식)

이 이야기는 데이터과학이라는 용어가 생겼을 때부터 데이터과학의 정의에 항상 설명되어 있는 내용입니다.

데이터과학은 모든 기술을 업무 문제를 해결하는데 집중합니다.

반면 데이터분석은 현재 데이터의 상태를 확인하고 검증하는 것으로 끝냅니다.

현실의 문제를 해결하려는 목적없이 기계학습 모델만 만들고 싶어하면 단순한 ML엔지니어이고 통계적 분석만 한다면 단순한 분석가가 되는 것입니다.

하지만 복잡하고 풀기 곤란한 현실의 비즈니스 문제에 개입하고 싶지 않으려는 사람들이 많은데 그 사람들은 도메인 날리지를 제외하고 나머지 부분만을 데이터과학이라고 주장합니다.

A/B 테스트를 95% 대 5% 비율로 해도 괜찮을까?

답부터 말하면

안 괜찮습니다.

사실 비율 보다는 샘플의 크기가 중요하지만 어쨌든 95%대 5%로는 A/B테스트는 문제를 만듭니다.

A/B테스트 흔히 온라인서비스에서는 버킷테스트라고 하는데 이 테스트에서 A와 B 두개의 샘플의 수가 서로 불균등하다고 하면 대부분의 통계학자들은 표정이 안좋아지며 심각하게 생각하지만 개발자들은 별것 아니라고 생각합니다.

이게 논란의 여지가 항상 있는 것이므로 조심스럽지만

A/B테스트는 통계학에서 나온 것이므로 통계학자들이 더 잘 알것이므로 이쪽을 더 신뢰하는 것이 맞습니다. 통계학자들은 경험과 이론을 통해 그게 왜 문제인지 설명하지만 개발자들은 그런 설명을 하지 않습니다.

개발자들은 근거를 말하지 않지만 통계학자들은 근거를 말합니다.

A/B 테스트, 버킷테스트는 여러개의 샘플에 각기 다른 처치(작용 또는 변화를 주는것)를 하고 그게 정말 효과가 있는 지 살펴보는 것이라는 것을 기억해야 합니다.

A/B 테스트는 샘플이 중요하다

A/B 테스트는 통계학에서 다루는 실험 운영 방법입니다. 실험계획법이라는 통계학 과목이 있습니다. 과목이 따로 있을 만큼 만만한 것이 아닙니다

통계학은 샘플을 매우 중요하게 생각합니다.
적어도 통계학파 중에 빈도주의자(Frequatist)들은 매우 중요하게 생각합니다.
그와 비교되는 다른 학파들도 있지만 이건 다음에 얘기하겠습니다.

샘플은 어떤 집합에서 일부를 떼어 낸 것을 말합니다.

통계학에서 샘플을 중요하게 생각하는 이유는 샘플을 통해서 원래 전체 데이터의 특성을 파악해야 하기 때문입니다. 샘플을 사용해서 원래 집합을 알아내려고 하는 이유는
대부분의 전체 데이터를 다 확인하는 것은 불가능하기 때문입니다.

“빅데이터 플랫폼도 있는데 전체데이터 확인을 왜 못하냐?” 라고 물어볼 수 있습니다. 잘못 이해한 것인데 거기서 말하는 전체데이터는 실제로 알고자 하는 사실을 얻어야 하는 대상의 전체가 아니기 때문입니다.
예를 들어서
어제까지 가입한 쇼핑몰 전체의 고객 데이터는 전체 데이터가 맞긴 하지만 쇼핑몰의 고객 전체는 아닙니다. 앞으로도 가입할 사람이 있을 것이고 탈퇴할 사람도 있을 것이기 때문입니다. 그런 관점에서 통계학에서 생각하는 전체 데이터를 얻는 것은 불가능하다고 할 수 있습니다.

어제까지 전체 고객 데이터는 통계학에서는 전체데이터가 아닌 그냥 매우 큰 샘플데이터입니다.

A/B테스트에서 A와 B는 각각 전체 모집단에 대한 샘플이라고 봅니다.

A/B테스트에서 샘플 수가 균등하지 않으면 통계 검정을 할 수 없는가?

그래서 A/B의 비율이 5:5로 균등하지 않으면 정확한 비교를 하지 못하는가?
라는 의문이 있을 것이다.
할 수는 있습니다.
다만 꽤 복잡한 방법을 써야 하고 정확하지 않은데다 선택한 검정 자체를 적용하는 것 자체가 맞는지 안맞는지는 확인하려고 하는 것은 노련하고 뛰어난 통계학자도 매우 어렵게 하는 것입니다.

간단하게 공식 몇 개 넣어서 계산하면 되는 것이 아닙니다.

그래서 이렇게 불균등한 샘플 비교를 최대한 피해야 합니다.

샘플 간의 성능 비교를 한다면 균등한 것이 낫다

균등하지 않은 샘플로 샘플의 불균형성을 극복하면서 테스트하는 것 보다 균형 샘플을 만들어서 테스트하는 것이 더 쉽고 돈도 더 적게 듭니다. 균등하지 않은 샘플로 서로를 비교하는 것은 일반적으로 실험계획이 잘못된 경우나 하지 못한 후시 테스트일 가능성이 높습니다.

A/B 테스트와 관련되었대고 하면 무조건 샘플 수를 맞추고 시작합니다.

불균등한 것이 뭐가 그리 문제인가?

샘플이라고해서 그렇게 거창한 것은 아닙니다.
A그룹에서 추출한 숫자들, B그룹에서 추출한 숫자들을 비교하는 것인데
샘플이 균등하지 않으면 크게 달라질 수 있는 것이 파라미터(모수, parameter)인데 평균과 분산입니다.
A/B테스트는 A와 B의 평균과 분산이 실험 후에 많이 차이가 나는지 아닌지를 보는 것입니다.
이때 샘플의 수 그러니까 숫자의 갯수가 많이지면 숫자의 갯수가 적을 때 보다 분산은 무조건 커집니다.
이게 자연적인 현상입니다.
그래서 샘플의 수가 50대 50으로 균등하지 않으면 샘플 수로 인해서 생길 수 있는 기본적인 분산의 차이를 보정하고 검정을 해야 하는데 보정이 매우 어렵고 보정을 해도 정확도가 떨어집니다.

실험결과를 잘못 해석하게 됩니다.
이런 결과로 결정을 하면 비즈니스에 큰 실패를 가져올 수 있습니다.

실험 자체를 잘못하는 것은 그 실험을 없었던 것으로 하면 되기 때문에 피해가 덜하지만
결과를 잘못해석하면 틀렸다는 것 자체를 의심하지 않기 때문에 큰 문제를 생깁니다.

한쪽을 언더샘플링(Under sampling)을 하면 어떤가?

크기(갯수)가 다른 두 샘플들이 있을 때 크기가 적은 샘플 수만큼을 크기가 큰 색플에서 도려내서 숫자를 맞추는 것이 언더샘플링(under sampling)이라는 방법입니다.
간단히 말하면
그냥 큰 쪽을 작은쪽의 크기 만큼 잘라서 맞추는 것입니다.
보통 자를 때 무작정 자르지 않고 랜덤으로 샘플링을 합니다. (확실하게 랜덤으로 분할 한 것과 같은 것으로 분할 할 수 있으면 랜덤 샘플링을 하지 않아도 됩니다. 이건 따로 설명하지요)

어쨌든 이러면 괜찮지 않은가?
라고 생각할 수 있는데
이것도 괜찮지 않습니다.

언더샘플링을 하는 순간 샘플의 모집단이 달라지게 됩니다. 샘플이 뽑힌 것의 자유도라는 것도 다르기 때문에 두 샘플은 비교하기 어렵게 됩니다.
부모가 낳은 형과 동생을 비교하다가 형과 동생의 아들인 조카를 비교하는 꼴인 것이다.
부트스트래핑을 쓰면 하게되면 이러 불균형에서 샘플링을 통해 문제를 해결할 수 있지만 역시 그 보다는 샘플 수를 맞추는게 편하고 낫습니다.

대부분의 버킷시스템은 샘플 수를 맞추도록 설계되어 있다

빅테크 회사들의 버킷시스템이 존재합니다. A/B테스트를 할 수 있도록 플랫폼이 갖춰줘 있고 샘플의 수 등을 수정할 수 있습니다.
저런 대형 기업들의 시스템에서도 기본으로 두 비교군의 샘플 수를 맞추도록 설계되어 있습니다.
다른 대기업들도 모두 마찬가지입니다.
그들은 왜 모두 그렇게 하는지 생각을 해보기로 합시다.
그냥 그렇게 하거나 단순한 전통이어서 그렇게 하는 걸이다 아닙니다.
그것이 통계적이고 과학적으로 실험의 결과를 오해석하지 않는 최선의 방법이기 때문입니다.

통계학자들이 무능하고 실력이 없으면서 복잡해 보이기 좋아하기 때문에 저렇게밖에 못한다고 생각할 수도 있지만.

버킷시스템에서는 언더샘플링이 가능하다

추가로 말하면 대부분의 버킷시스템은 사용자의 ID 또는 비식별ID를 비트연산을 통해 그룹을 나눠서 관리하도록 되어 있습니다.

따라서 많은 쪽의 비트 몇개를 무시해서 언더샘플링을 하면 샘플비교를 할 수 있습니다.
조금 복잡하니 자세한 것은 따로 설명하겠습니다.

참고

A/B테스트에 대해 포스트를 올린적이 있습니다. 시간이 있다면 자세한 내용은 그걸 참조하세요.

추천시스템을 개선해서 CTR을 올리면 매출도 증가할까?

CTR은 Click Through Rate 입니다.
클릭수/노출수x100으로 계산하는데
짧게 말하면 노출대비 클릭수의 비율이라고 할 수 있습니다.
검색결과 또는 추천시스템의 성과를 확인하기 위한 가장 기본적인 지표로 많이 쓰입니다.

본론으로 들어가서
광고 노출, 검색 결과를 잘 조절해서 CTR을 획기적으로 올리는 방법은
별로 없습니다.

보통 제안하는 상품이나 검색 결과가 오디언스(사용자 또는 고객)의 관심을 끌지 못하면 CTR은 떨어집니다. 관심이 없으면 클릭을 하지 않기 때문입니다.

이커머스에서도 CTR은 매우 중요합니다. 이커머스에서는 추천상품 모듈이 있어서 검색이나 특정 상품을 볼 때 다른 추천 상품을 제안해서 구매를 유도합니다. 그 외에 검색해서 나오는 상품들도 사실상 추천이라고 할 수 있습니다. 검색 결과도 원칙적으로는 추천입니다.

추천시스템(Recommendation system)을 업그레이드 해서 개선에 성공한다면, 그리고 CTR을 올리면 과연 매출이 올라가느냐?라는 의문을 가질 수 있습니다.
이게 정말 그러냐는 것인데

답: 그럴 수도 있지만 아닌 경우가 더 많습니다.

우선 개발자 또는 ML엔지니어가 가장 많이 착각하는 것이 “CTR을 올리면 당연히 매출도 올라가겠지” 라고 단정해서 짐작하는 것입니다.
하지만 이 짐작은 그 자체로는 과학적 근거가 없습니다.
게다가 CTR은 비즈니스 업종, 제품 카테고리(품목), 시즌에 따라서 각기 다른 양상을 보입니다.
매우 복잡하지요.

더 구체적으로 설명하면

상품 노출 후 구매까지의 단계는
추천 상품 노출 -> 클릭 -> 구매
로 됩니다.

그리고 클릭율과 전환율의 정의를 보면

노출 -> 클릭으로 가는 비율을 계산한 것이 CTR (클릭율)
클릭 -> 구매로 가는 비율을 계산한 것이 CVR (전환율)

다시 원래의 질문으로 돌아가서 CTR을 높이면 매출이 정말 올라가느냐?가 맞으려면 CTR을 올리고 CVR이 그대로 이거나 증가해야 합니다.

CTR이 많이 올라갔으면 CVR은 오히려 조금 떨어져도 됩니다. 높은 CTR이 CVR의 감소를 만회해 줍니다.

하지만

모델을 개선해서 CTR을 올렸는데 CVR이 줄어드는 경우가 꽤 많이 생깁니다.
CVR과 CTR이 음의 상관관계를 가지는 경우가 많기 때문입니다.
이것 때문에 분명 CTR은 높아졌는데 정작 매출이 늘지 않게 됩니다.

그래서 이것이 클릭예측모델(클릭 모델)을 만든 후에 구매예측모델을 만드는 발단이 되기도 합니다. 구매예측모델은 더 만들기 어렵고 잘 안됩니다. 이것은 나중에 따로 얘기하기로 합니다.

마케팅과 행동과학 측면에서 생각하는 것을 고려해야 합니다.

CTR이 오른다는 것은 사람들이 추천한 제품에 관심을 많이 보였다는 것입니다.
그런데
사람들에게 많은 관심을 받는 제품이 반드시 잘 팔리는 제품은 아닙니다.
예를 들어
“휘어지는 4K 200인치 TV” 같은 것은 많은 사람들에게 관심을 갖도록 할 수 있지만
구매하는 사람은 많지 않습니다.
“생글생글 생수” 이런 생수는 사람들의 관심을 끄는 제품이 아니라서 CTR은 낮지만
CVR은 매우 높은 제품입니다.

TV는 고관여제품이고 생수는 저관여제품입니다.

고관여제품: 사는데 고민을 많이 하고 비싼 제품. 구매 후 실패하면 위험 부담이 큰 제품
저관여제품: 사는데 고민을 적거 하고 싼제품. 구매 후 실패를 걱정하지 않는 제품

사람들은 생수에 대해서 잘 알고 있고 동일한 제폼이나 유사한 제품을 반복해서 구매합니다.
그래서 이런 저관여제품의 구매는 망설임이 없이 구매합니다.

이외에도 여러 문제가 있다.
그래서 추천시스템의 성과를 단순히 CTR로 측정해서는 안되고 추천해서 사람들이 클릭한 것만으로 모델의 가치평가를 하게 되면 모델을 론칭하고 나서 비즈니스에서는 실제 개선이 없는 상황을 맞이 하게 됩니다.

추천시스템의 모델링에 집착해서 기계학습 모델의 개선에만 몰두하는 곳이 매우 많은데
위와 같이 실제 비용효율이 나지 않는 경우를 많이 보았습니다.
대부분의 모델을 새 알고리즘으로 교체하거나 피처 엔지니어링을 통해 개선하고 나면 아주 적은 CTR의 개선을 볼 수 있겠지만 전체 매출에는 통계적으로 무의미한 미미한 증가만 얻게 됩니다.

비용효율이 안나오게 되고 이런 일이 반복되면 비즈니스 담당자로부터 모델과 기술자는 신뢰를 잃게 됩니다.

무작정 CTR을 올리는 모델을 잘 만들기만 하면 비즈니스는 대박이 나고 나는 스타가 될 수 있을꺼야 라고 생각하는 MLE나 데이터과학자가 많습니다.

해보면 알겠지만
세상은 그렇게 만만하지 않습니다.

docker comose stop과 down의 차이

Docker를 사용하는 것이 이미 일반화되었지만 가끔 코맨드의 기능을 명확하게 기억하지 못할때가 있다.

stop과 down의 차이인데 다음과 같다.

  • stop 은 컨테이너를 잠시 멈추는 것뿐이다.
  • down 은 컨테이너와 컨테이너에 연결된 네트워크를 멈추고 삭제까지 한다.

도커이미지를 구성할 때 down 명령을 사용할 경우를 대비해서 설명에 네트워크 설정에 대한 것도 문서에 자세히 기록할 필요가 있다. 익숙하다고 방심하면 빠뜨려서 문제를 만드는 경우가 많아진다.

LLM은 스스로 데이터분석을 할 수 있을까?

LLM

기술통계와 같은 설명기반의 분석은 할 수 있습니다.
연과분석과 같은 원인을 파악하고 통찰을 얻는 것은 할 수 없습니다.

LLM은 데이터분석을 할 수 없다고 할 수 있습니다.
데이터분석가들이 말하는 능동적인 고급데이터 분석에 대한 것을 말한다면 그렇습니다.

데이터분석은 결과물에 따라 2가지로 나눌 수 있는데

  • 데이터 그 자체에 대해 설명하는 탐색적데이터분석
  • 데이터로부터 알고자 하는 사실을 확인하고 인과, 요인 분석을 통해 어떤 결정을 하는데 필요한 근거 자료를 찾는 것

LLM은 인과분석과 같은 논리적 사고를 할 수 있게 고안된 것이 내부에 없습니다.
대형 뉴럴네트워크에서 대량의 학습이 되면 마치 인과추론과 사고를 하는 것 처럼 만들 수 있는데
그것은 하는 것 처럼 보이는 것이지 진짜 하는 것이 아닙니다.
아직 LLM이 사고를 하고 데이터분석을 한다는 것이 증명된 적도 없습니다.

그래서 LLM은 데이터를 넣어주는 것 만으로는 인과분석과 같은 고급데이터 분석을 하지 못합니다.
다만 프롬프트를 단계적으로 입력하거나 절차형으로 넣어서 (CoT) 비슷하게 할 수는 있지만
인간과 같은 깊은 고찰에서 나오는 결론과 답을 내주지는 않습니다.

ChatGPT의 코드인터프리터와 같은 별도의 모듈을 이용하면 하는 것처럼 보이도록 하는게 가능하지만 근본적으로 데이터 분석을 하는 것은 아닙니다.

LLM은 아직 스스로 고뇌하고 고민하는 사고를 하지 못합니다.
데이터분석의 결과물은 인간의 깊은 고민과 사고의 결과물입니다.

mysqldump할 때 lock 방지하기

mysqldump를 하면 DB에 lock를 걸게 된다. 기본 설정이 그렇게 되어 있다.
서비스 운영중인 데이터베이스에 그런 것을 하면 큰 문제가 생긴다.
mysqldump를 할 때 lock을 걸지 않도록 하는 옵션을 해야 한다.

mysqldump를 할 때 자주하는 것이 아니라서 실수하기 쉬운데 다음과 같이 옵션을 주고 처리할 수 있다.

mysqldump --skip-add-locks --skip-lock-tables db table > dump.sql

덤프하는 중에도 다른 세션에서 insert, update, delete 가능하다.

mysqldump --single-transaction  db table > dump.sql

덤프하는 중에도 다른 세션에서 insert, update, delete 가능하다.

mysqldump --lock-tables  db table > dump.sql

덤프하는 중에 다른 세션에서 insert, update, delete 불가능하다.

LLM은 스스로 사고할 수 있는가?

LLM이 스스로 사고를 하는지에 대한 것은 이제 더 이상하지 않는 조금 지난 주제입니다.

아직까지 그런 생각을 하는 분들이 있어서 포스트를 올려둡니다.

현재의 LLM은 구글의 트랜스포머 AI 아키텍쳐를 계승받은 AI모델 중에 초대량의 학습데이터와 파라미터를 가진 모델들을 말합니다.

그 중 대표적인 것이 트랜스포머에서 생성형 부분만 따로 분리해서 만든 모델인 GPT입니다. 그 외에 구글의 Palm이나 메타의 LLamma가 있지만 구조는 차이가 별로 없습니다.

LLM은 Large Language Model의 약어입니다. 이름이 내포하듯이 LLM은 언어처리를 위한 인공지능 모델입니다. 언어처리와 관련된 것 외의 것을 하도록 설계된 것은 구조만 볼때는 거의 없습니다.

LLM은 사고를 하지 못합니다.
혹시 LLM은 의식을 가지고 있거나 사고를 할 수 있는것이 아닐까하는 의심에
빅테크 회사와 많은 과학자들이 테스트를 했지만 그 증거가 있다는 발표나 연과결과는 없습니다.

오히려 관련이 없다는 연구결과만 있습니다.

LLM은 의식이 없습니다.

영혼이 없습니다. 사고를 하지 못하연 영혼도 없고, 의식이 없으면 자아도 없습니다.

이 역시 의식이 있는지 테스트한 연구가 있었지만 의식이 있다는 결론이 난 것은 없습니다.

LLM은 계산을 하지 못합니다.

LLM은 단순한 사칙연산도 수리적으로는 하지 못합니다.
1 + 2 = 3이라는 대답을 LLM이 한다고 계서 계산을 했다고 생각해서는 안됩니다.
문제에 대한 답을 외웠다고 생각해야 합니다.

트랜스포머의 구조에 대해서 이해하고 있다면 이런 것들이 당연히 되지 않는 다는 것을 알게되는데 이해가 부족하게 되면 그와 같은 주장을 하게됩니다.

그럴만도 한데 LLM에 프롬프트를 주면 마치 생각을 하는 것 처렁 대답하기 때문입니다.
하지만 그것은 명백한 착각입니다.


아직까지 LLM이 사고를 가지고 있거나 의식이 있다는 것을 증명한 사람은 없으며
실제로 그런 결과를 LLM이 내놓는 경우도 없습니다.

그러니 그런 착각으로 LLM의 가능성에 접근하게 되면 큰 낭패를 보게 됩니다.

더닝크루거 현상이라는 유명한 신드롬에 대한 용어가 있습니다.
아는 만큼 보이고 어설픈 지식이 얼마나 큰 착각과 오해를 불러일으키는지에 대한 용어입니다.

R에서 T-test, 카이제곱으로 가설검정 결과 간단하게 확인하기

R언어에서 T-test와 Chi-square 검정을 하는 간단한 스니펫입니다.
간단한 것이지만 자주 쓰지 않으면 너무 기본이라서 오히려 기억이 잘 나지 않기 마련입니다.

t.test와 chisq.test 함수 모두 list(object)를 리턴하게 되고 멤버 변수인 p.value에 접근해서 P값을 알아낼 수 있습니다.

# T-test two vectors
a <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
b <- c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)

t.test(a, b)

# 결과에 대한 자세한 설명을 화면에 출력해봐
t.test(a, b)$p.value
t.test(a, b)$statistic
t.test(a, b)$conf.int
t.test(a, b)$estimate
t.test(a, b)$null.value
t.test(a, b)$alternative
t.test(a, b)$method
t.test(a, b)$data.name
t.test(a, b)$conf.int[1]
t.test(a, b)$conf.int[2]

# chi-square test for two vectors

a <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
b <- c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
chisq.test(a, b)
if (chisq.test(a, b)$p.value < 0.05) {
  print("귀무가설 기각")
} else {
  print("귀무가설 채택")
}

Azure OpenAI GPT4-Turbo 지원 리전

2023년 11월 17일부로 Azure Openai에서 GPT4-Turbo를 지원하는 리전 목록입니다.

GPT-4 Turbo 모델을 Azure에서 사용하기 위해서 계속 기다렸지만 소식이 없어서 조사해봤더니 토쿄를 제외한 다른 리전에서는 지원을 하고 있었네요.

한국에서는 거리가 가까운 도쿄 리전을 사용하기 마련인데 도쿄는 아직까지도 GPT4-Turbo 모델을 지원하지 않고 있네요.

Azure에서 GPT4 Turbo를 쓰려면 리전을 사용이 가능한쪽으로 옮겨야 할 것 같습니다

ModelRegions
GPT-4 Turbo
(gpt-4-1106-preview)
Australia East
Canada East
East US 2
France CentralNorway EastSouth India
Sweden Central
UK SouthWest US
GPT-3.5 Turbo 1106
(gpt-35-turbo-1106)
Australia East
Canada East
France CentralSouth India
Sweden Central
UK SouthWest US

참고: https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/azure-openai-service-launches-gpt-4-turbo-and-gpt-3-5-turbo-1106/ba-p/3985962

R로 베타 분포 그래프그리기 – Plotting Beta Distribution

베타분포는 시행에 따른 성공결과에 대한 분포로 베이지안의 기본이 되며 여러가지로 사용이 많이 되는 분포입니다.

강화학습이나 Multi Armed Bandit 에서도 나옵니다.
베타분포를 이해하려면 플롯을 그려보면 도움이 많이 됩니다.

베타분포를 플롯팅하는 R코드입니다.

# Install required package (if not already installed)
install.packages("ggplot2")
# Load the required library
library(ggplot2)
plot_beta_dist <- function(success_count, fail_count) {    # Generate a sequence of x-values
    x <- seq(0, 1, length.out = 1000)
 
    # Calculate the probability density function values
    pdf_values <- dbeta(x, success_count, fail_count)
 
    # Create a data frame with x and pdf values
    data <- data.frame(x = x, pdf = pdf_values)
 
    # Plot the Beta distribution
    ggplot(data, aes(x)) +
    geom_line(aes(y = pdf), color = "blue", size = 1) +
    xlab("x") +
    ylab("Probability Density") +
    ggtitle("Beta Distribution") +
    theme_minimal()
}
 
plot_beta_dist(10, 10)
plot_beta_dist(100, 100)
plot_beta_dist(1000, 1000)

You tried to access openai.ChatCompletion, but this is no longer supported in openai>=1.0.0

openai 1.0.0 이상의 버전에서는 openai.ChatCompletion으로 completion을 생성할 수 없고

먼저 client를 생성한 후 client에서 completion을 받도록 변경되었습니다.

그와 관련된 오류메세지입니다.

구버전의 openai client 용 코드를 1.0.0보다 높은 버전의 openai client에서 사용하고 있다는 메시지입니다.

아래 링크의 문서를 확인해 보시고

https://github.com/openai/openai-python

다음과 같은 방식으로 기존 코드를 수정해 주어야 합니다.

from openai import OpenAI

client = OpenAI(
    # defaults to os.environ.get("OPENAI_API_KEY")
    api_key="My API Key",
)

chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": "Say this is a test",
        }
    ],
    model="gpt-3.5-turbo",
)

Pyperclip could not find a copy/paste mechanism for your system.

Pyperclip을 사용할 때 다음과 같은 에러가 발생할 때가 있다.

Pyperclip could not find a copy/paste mechanism for your system.

필요한 패키지가 리눅스에 설치되어 있지 않아서 그렇다.
필요한 패키지를 설치해주자.

sudo apt-get install xsel
sudo apt-get install xclip
pip install gtk
pip install PyQt4

이 패키지는 지저분한 패키지를 같이 설치한다.
그래서 꼭 써야하는 것이 아니라면 안쓰는 것이 좋다.

참조: https://pyperclip.readthedocs.io/en/latest/

GPT assistant file의 업로드 오류 메세지

OpenAI GPT API로 assistant file을 업로드하다 오류가 발생하면 아래와 같이 매우 장황한 설명을 합니다.

오류의 대부분은 다음과 같은 이유가 대부분입니다.

  • PDF형식이 이상해서 텍스트를 추출하지 못함
  • 파일이 깨짐
  • 파일 요량 초과

메세지는 기록을 위해서 여기에 저장해 둡니다.

It appears that the content extracted from the PDF file is not meaningful text, but rather a mix of symbols and characters, which likely means that the text within the PDF is either stored in a non-standard format, such as images or custom encoding, or the file may contain primarily images rather than text.

Unfortunately, without a more sophisticated PDF analysis tool that can handle optical character recognition (OCR) to interpret any images as text, or specific knowledge of the file’s encoding, we might not be able to extract readable content from the PDF in this environment.

Nonetheless, if the PDF file contains information on how to create an account and register app information with “xxxxxxxxx,” you would typically follow the instructions provided within the document, which usually involve navigating to a specific URL and filling out forms with the necessary information.

If you have a specific tool or method in mind for attempting to parse the PDF content further, or if the file should be used in a particular context, please let me know and I’ll do my best to assist you further.

*****************************************************************************

The hexadecimal representation of the first few bytes of the file is `’25504446’`, which corresponds to the magic number for a PDF (Portable Document Format) file. The magic number `0x25504446` stands for `%PDF` in ASCII, which is the signature for PDF files.

Now that we know it’s a PDF file, we can attempt to extract its text content (if it contains any) using a PDF reading library. Let’s try that next.

*****************************************************************************

The file does not have an extension, making it challenging to determine its type based on the name alone. Since I wasn’t able to open it as a text file directly due to an encoding issue, I will now attempt to use a different method to read the file as binary data and then analyze the first few bytes to infer the file type. This is often referred to as checking the “magic number” of the file, which can give us clues about the file format. Let’s proceed with this method.

*****************************************************************************

My apologies for the confusion, it seems that the python-magic module I intended to use to detect the file type is not available in this environment. Let me try another approach to determine the file type. I will first attempt to check the file extension and then try a different way to check the content type if necessary.

*****************************************************************************

It looks like the file may not be a text file or it might not be encoded in UTF-8. The next step is to try to infer the file type or encoding. Let’s start by attempting to detect the file type based on its content.

I will now attempt to analyze the file to identify its type and then proceed accordingly. If it is a binary file, such as an image or an executable, we won’t be able to directly view its content as text. If it’s an archive or a document, we might need to take additional steps to extract and view the content. Let’s determine the file type first.

우분투에 포스트그레스 설치 – Install PostgreSQL on Ubuntu Linux

아래의 순서로 하면됩니다.

# Create the file repository configuration:
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

# Import the repository signing key:
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

# Update the package lists:
sudo apt-get update

# Install the latest version of PostgreSQL.
# If you want a specific version, use 'postgresql-12' or similar instead of 'postgresql':
sudo apt-get -y install postgresql

자세한 내용은 아래 원문을 참고하세요.

https://www.postgresql.org/download/linux/ubuntu/

Rstudio server에서 Copilot 사용하기

Rstudio 2023년 9월 28일 릴리즈 버전 이후부터는 Github copilot을 정식지원합니다.

neovim의 plugin을 이용해서 연동한 것인데 깔끔하게 잘 작동합니다.

Rstduio desktop을 설치하면 옵션에서 설정하고 로그인만한 하면 그냥 잘 작동하는데 Rstudio server는 옵션을 활성화하려고 하면 어드민이 허용을 해주지 않았다는 메세지가 나옵니다.

그래서 추가 설정이 필요합니다.

리눅스 서버에 ssh로 접속해서 /etc/rstudion/rsession.conf을 열어줍니다.

이 파일을 Rstudio server가 사용자별로 세션을 새로 로딩할 때 초기화하기 위해 사용하는 파일입니다.

sudo vim /etc/rstudio/rsession.conf

그리고 다음 줄을 추가해줍니다.

copilot-enabled=1

옵션에서 github copilot을 활성화하고 로그인을 합니다.

아래와 같이 나오면 된 것입니다.

Azure OpenAI GPT API 의 민감정보 필터링 정보

GPT API중 completion 결과 중에 hate, self_harm, sexual, violence 이 4가지에 대한 민검정보 필터링에 대환 결과 여부와 등급이 보이는 것을 볼 수 있습니다.

이 정보를 활용하면 민감한 정보에 대한 답 자체를 보여주지 않거나 할 수 있습니다.

{
    "index": 0,
    "finish_reason": "stop",
    "message": {
        "role": "assistant",
        "content": "...",
    },
    "content_filter_results": {
        "hate": {"filtered": false, "severity": "safe"},
        "self_harm": {"filtered": false, "severity": "safe"},
        "sexual": {"filtered": false, "severity": "safe"},
        "violence": {"filtered": false, "severity": "safe"},
    },
}

한국어 형태소 분석기 – Bareun 바른

새로운 한국어 형태소분석기 바른입니다. 이런 한국어 NLP툴킷의 공개는 상업적이던 비상업적이던 늘 환영할 만한 것입니다. 우리나라의 NLP에 대한 기술은 국제적으로 매우 뒤쳐저 있기 때문입니다.

바른형태소분석기는 바른팀(바이칼에이아이, 한국언론진흥재단 공동)에서 제작한 것이라고 되어 있습니다.

간단하게 테스트해 보니 은전한닢(MeCabKR, 메카부 한국어 버전)과 비슷한 성능으로 보입니다.

사용성이 좋아 보여서 다음번에 테스트를 더 해본 후에 사용할 일이 있으면 해보려고 합니다.

하지만 요즘 LLM의 발전속도가 너무 빨라서 쓸일이 없을 것 같기도 합니다만.

https://bareun.ai/

Adsense의 GDPR 메세지 생성 요청

블로그에 애드센스를 붙이긴 했지만 수입이 거의 없기 때문에 접속을 자주 안합니다.

오랜만에 접속했더니 아래와 같은 경고 메세지가 보입니다.

내용은 아래에 있습니다.

2024년 1월 16일부터 EEA 및 영국 사용자에게 광고를 게재하는 모든 게시자는 Google에서 인증한 동의 관리 플랫폼(CMP)을 사용해야 합니다. Google의 자체 동의 관리 솔루션을 포함하여 Google에서 인증한 CMP 이면 어떤 것이든 이 목적으로 사용할 수 있습니다. Google의 동의 관리 솔루션을 사용하는 데 관심이 있으면 먼저 GDPR 메시지를 설정하세요.

GDPR 메시지 만들기를 진형하면 생성 화면과 함께 메세지 만들기에 들어가는데 이 작업을 하고 나면 이제 GDPR 메세지가 접속자에게 보이게 됩니다.

GDPR을 준수하면 개인을 추적할 수 없습니다.
GDPR을 준수하지 않으면 애드센스의 리타겟팅 추적 광고는 보이지 않게 됩니다.
GDPR메세지가 보이면 접속자는 자신을 추적하게 허용할지 아닐지를 결정할 수 있고 추적을 허용하지 않게 하면 사이트에서 강제로 이탈되거나 정보의 일부만 볼 수도 있습니다.

그리고 개인을 추적하지 않아도 광고는 계속 내보냅니다.
아무 광고나 보이게 된다는 점의 차이만 있을 뿐입니다.

Azure OpenAI API로 GPT 사용하는 예제

Azure cloud (애저 클라우드, 이하 Azure)에서 지원하는 OpenAI API로 GPT를 사용하는 방법입니다.

OpenAI에서 제공하는 Python 클라이언트 패키지를 설치해서 똑같이 사용하면 됩니다.
별도의 패키지가 필요하지는 않습니다.
OpenAI의 Python 패키지에 이미 Azure를 지원하기 위한 코드가 들어 있습니다.
Microsoft가 OpenAI의 가장 큰 투자자이고 협력관계이기 때문인 것 같습니다.

단, openai의 API를 사용할 때와 다른 점은 다음과 같습니다.

  • openai를 처음 초기화 할 때 다른 Azure OpenAI에만 필요한 설정값 필요
  • completion을 생성할 때 파라미터가 조금 다름

자세한 내용은 애저(Azure)에서 제공하는 문서를 참고하면 됩니다.

예제는 아래의 소스 코드를 참고하세요.

import os
import openai
import toml
import base64


openai.api_key = "  ***** 본인의 API키 ***** "
openai.api_base = "https://instance-openai-0.openai.azure.com/"
openai.api_type = "azure"
openai.api_version = "2023-07-01-preview"
deployment_id: str = "deployment-gpt-4-32k"  # 본인의 배포 ID로 변경

instructions: list[dict] = [
    {"role": "system", "content": "you are an assistant for software engineers"},
]

messages: list[dict] = [
    # {"role": "user", "content": "What is ticket price for cruise ship"}, # for function_call
    {"role": "user", "content": "샌프란시스코의 관광명소를 알려주세요."},  # for normal reply
]

response: openai.ChatCompletion = openai.ChatCompletion.create(
    # model="gpt-4", # this is for the OpenAI API, not for the Azure API
    deployment_id=deployment_id, # this is for the Azure API, not for the OpenAI API
    # engine=deployment_id, # same as above
    messages=instructions + messages,
    functions=[
        {
            "name": "get_ticket_price",
            "description": "Get ticket price of cruise ship",
            "parameters": {
                "type": "object",
                "properties": {
                    "start_location": {
                        "type": "string",
                        "description": "Start location of the cruise ship",
                    },
                    "end_location": {
                        "type": "string",
                        "description": "End location of the cruise ship",
                    },
                },
            },
            "required": ["start_location", "end_location"],
        },
    ],
    function_call="auto",
    temperature=0.90,
    max_tokens=800,
    top_p=0.99,
    frequency_penalty=0,
    presence_penalty=0, 
    stop=None)

if len(response.choices) > 0:
    if response.choices[0].finish_reason == "function_call":
        print("=====================================")
        print("function_call is called")
        print(response.choices[0].message)
        print("=====================================")
    else:
        print("=====================================")
        print("reply is returned")
        print("role: ", response.choices[0].message.role)
        print("message: ", response.choices[0].message.content)
        print("=====================================")
else:
    print("No response.")

Github에도 소스를 올려놨으니 필요하면 편하게 가져가세요.

https://github.com/euriion/llm-materials/blob/main/azure-openai-api/azure-openai-api-test.ipynb

초거대 언어 모델이란? LLM

간단한 요약 정리 LLM

LLM : Large Language Model의 약어로 한국어로 초거대 언어 모델이라고 합니다.

Large라는 단어가 초거대라는 뜻은 아니지만 어느덧 그런 의미로 쓰게 되었으며 이제는 LLM을 다 묶어서 초거대언어모델이라고 하는 일반명사로 생각하는 것이 좋습니다.

LLM은 딥러닝(Deep Learning)으로 만든 파라미터가 약 1천억개가 넘는 언어 처리를 위한 모델을 말합니다.

언어 처리는 언어 번역, 요약, 생성, 문장 완성, 감성 분류, 키워드 추출, 개체명 인식 같은 것들입니다.

LLM에서 말하는 파라미터는 딥러닝에서 레이어로 데이터가 흘러 갈 때 곱셈을 해주는데 쓰는 실수형 가중치 값들을 말합니다.

파라미터가 약 1천억개가 넘어가게 되면 기존 언어모델은 보여주지 않았던 매우 창발적인 답을 하고 마치 인간인 것처럼 지능적으로 답을 하는 특성을 가집니다.

현재 시점으로 LLM으로 가장 유명한 것은 GPT, BERT, PALM이 있습니다.

모두 구조와 학습데이터가 다르고 성능도 다듭니다.

이 외에도 수 만개의 LLM 모델이 있으며 각기 따로 구조와 특징을 공부해야 합니다.

OpenAI API – GPT function calling 사용법

GPT function calling

OpenAI의 GPT API에서 얼마전부터 새롭게 제공하는 function calling 기능에 대한 설명입니다.

GPT function calling은 게임 체이저(Game changer)라고 블릴 만큼 굉장히 편하고 유용한 기능입니다. 이 기능을 이용하면 괜찮은 GPT 응용 애플리케이션을 매우 간단하게 만들 수 있습니다.

GPT function calling 설명

GPT function calling을 GPT에게 프롬프트와 함께 함수의 정의 목록을 함께 전달하면 GPT가 프롬프트를 보고 전달된 함수 중 하나를 호출해야 한다고 판단하면 그 중 하나를 호출해서 결과를 자신에게 전달해 달라고 하고 그 전달된 결과를 입력 받아 최종 메세지를 만드는 것을 말 합니다.

간단하게 플로우를 그려 보면 다음과 같습니다.

  1. GPT에게 프롬프트(질문)과 함께 함수 목록을 전달
  2. GPT가 프롬프트를 보고 함수를 실행 안해도 되면 그대로 메세지를 답변
  3. 만약 함수를 실행해서 그 결과가 필요하다면 함수를 실행해달라는 결과를 리턴
  4. GPT가 호출해달라고 한 함수를 사용자가 호출해서 결과값을 GPT에게 주고 다시 호출
  5. GPT가 이전의 프롬프트와 함수의 결과를 다 합쳐서 메세지를 만들어서 전달
  6. 만약 5에서 다시 다른 함수를 호출해야 한다면 3번으로 가게 됨

GPT function calling 예제 코드

아래 Python 코드를 살펴보시면 됩니다. 무척 쉽습니다.

중요한 점은 콘텍스트를 계속 유지해줘야 한다는 것입니다.

그래서 과거의 대화내역 뒤에 함수의 결과값을 다시 붙여줘야 제대로 대답합니다.

import openai
openai.api_key = "***** openai api key *****"

chat_completion: openai.ChatCompletion = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[
        {
            "role": "system",
            "content": "your name is Ironman. you anser in Korean",
        },
        {
            "role": "user",
            "content": """What is the weather like today?""",
        }
    ],
    functions=[
        {
            "name": "get_wether",
            "description": "get wether information",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "city or nation name",
                    }
                },
                "required": ["location"],
            },
        }],
    function_call="auto",
)

if chat_completion.choices[0].finish_reason == "function_call":
    function_name = chat_completion.choices[0].message.function_call.name
    functoin_arguments = chat_completion.choices[0].message.function_call.arguments
    # 함수 실행 부분을 추가
    # function_result에는 함수를 실행하고 난 결과값을 넣어준다.
    function_result = "function result"

    messages = [
        {
            "role": "system",
            "content": "your name is Ironman. you anser in Korean",
        },
        {
            "role": "user",
            "content": """What is the weather like today?""",
        },
        {
            "role": "function",
            "name": function_name,
            "content": function_result
        }
    ]
    
    second_chat_completion: openai.ChatCompletion = openai.ChatCompletion.create(
        model="gpt-4",
        messages=messages,
    )
    result_message = second_chat_completion.choices[0].message.content
else:
    result_message = chat_completion.choices[0].message.content

print(result_message)

BigQuery로 KNN 최근접 이웃 계산하기

BigQuery로 Consine similarity를 계산해서 KNN 최근접 이웃을 계산하는 예제 코드입니다.

KNN = K Nearest Neighbor = 최근접 이웃
최근접 이웃은 기계학습에서 매우 오래된 기법입니다. 간단하지만 매우 정확한 시스템이지만 데이터프로세싱에 많은 자원이 소모되기 때문에 잘 사용되지는 않습니다.

Cosine Distance함수는 BigQuery에서 빠른 것을 제공을 해주기 때문에 따로 만들지 않고 제공하는 것을 그냥 쓰면 됩니다.

하지만 결국 BigQuery를 쓴다 해도 cross join을 해야합니다.

아무리 빅쿼리라고 해도 처리하는 데이터가 조금만 커도 cross join은 잘 실행되지 않습니다.
그래서 빅쿼리로 하는 KNN은 실용성이 있다고 보기는 어렵습니다.

작은 데이터에 대해서만 가능하기 때문에 그 점을 참고하시기 바랍니다.

WITH tbl_left AS (SELECT group_id, word AS word1, vector AS vector1
              FROM recsys.recsys_word2vec
              WHERE _PARTITIONTIME IS NOT NULL
              AND group_id = '12345'
              )
   , tbl_right AS (SELECT group_id, word AS word2, vector AS vector2
              FROM recsys.recsys_word2vec
              WHERE _PARTITIONTIME IS NOT NULL
              AND group_id = '12345'
              )
select a.group_id, a.word1
, ARRAY_AGG(b.word2 ORDER BY ML.DISTANCE(a.vector1, b.vector2, 'COSINE') DESC LIMIT 50) as nn50
FROM tbl_left a
               JOIN tbl_right b
                    ON a.group_id = b.group_id AND a.word1 != b.word2
GROUP BY a.group_id, a.word1
;

유용한 리눅스 커맨드 Linux Command List


리눅스 커맨드는 잘 배우면 간단한 작업을 즉시 하기에 매우 편리하고 좋지만

제대로 신경쓰지 않으면 좀처럼 익히기 쉽지 않습니다.

적응하기 어렵습니다. 그래서 시간 날 때 연습하고 연마해야 합니다.

배울 때는 고생스럽지만 배우고 나면 생산에 매우 큰 도움이 되는 도구가 됩니다.

능력있는 개발자, 엔지니어가 되려면 필수 명령어는 반드시 외워서 사용해야 합니다.

잘 정리된 문서가 있어 여기 링크를 올려 둡니다.

https://github.com/jlevy/the-art-of-command-line/blob/master/README-ko.md

Database CTE (Common Table Expression)

SQL에는 쿼리를 실행할 때 그 순간만 사용할 테이블을 잠깐 만들어서 사용할 수 있습니다.

이때 JOIN절에서 임시 테이블을 만드는 방법과 select하기 전에 with절로 임시 테이블을 만드는 방법이 있습니다.

쿼리 내에서 임시 테이블을 만드는 방법 2가지

  • 인라인뷰(Inline view): Join 구문에서 select를 사용해서 쿼리를 실행하고 이름을 붙여 테이블 처럼 사용
  • CTE (Common Table Expression): select하기 전에 with절로 select 구문을 묶어서 이름을 붙이고 공통 테이블처럼 사용

CTE의 장점은 한 번 작성하고 뒤에서 이름을 이용해서 여러번 참조할 수 있다는 장점이 있습니다.

다시 정리하면

CTE (Common Table Expression)

CTE (Common Table Expression)는 SQL 쿼리에서 일시적으로 사용되는 결과 세트를 정의하는 방법입니다. CTE는 복잡한 쿼리를 간단하게 만들고, 코드를 재사용하며, 가독성을 높여주는 도구입니다. CTE는 ‘WITH’ 절을 사용하여 정의되며, 이어지는 SELECT, INSERT, UPDATE, DELETE 문에서 참조할 수 있습니다.

MariaDB에서 CTE를 사용한 예제:

단순한 CTE 예제 (사용자 정보 가져오기):

WITH user_cte AS (   SELECT id, name, age   FROM users ) SELECT * FROM user_cte;

이 예제에서는 user_cte라는 CTE를 생성하고, users 테이블에서 id, name, age를 가져옵니다. 그 다음, user_cte를 참조하여 결과를 가져옵니다.

재귀 CTE 예제 (계층적 카테고리 정보 가져오기):

WITH RECURSIVE category_cte (id, parent_id, name, depth) AS (   SELECT id, parent_id, name, 0   FROM categories   WHERE parent_id IS NULL   UNION ALL   SELECT c.id, c.parent_id, c.name, p.depth + 1   FROM categories c   JOIN category_cte p ON c.parent_id = p.id ) SELECT * FROM category_cte ORDER BY depth, id;

이 예제에서는 category_cte라는 재귀 CTE를 사용하여, 계층적 카테고리 정보를 가져옵니다. 초기에는 상위 카테고리(즉, parent_id가 NULL인) 정보를 가져온 후, UNION ALL을 사용하여 하위 카테고리 정보를 가져옵니다. 그 다음, category_cte를 참조하여 결과를 가져옵니다.

다중 CTE 예제 (사용자 정보와 주문 정보 동시에 가져오기):


WITH user_cte AS (<br>  SELECT id, name, age<br>  FROM users<br>),<br>orders_cte AS (<br>  SELECT id, user_id, total<br>  FROM orders<br>)<br>SELECT u.name, u.age, o.total<br>FROM user_cte u<br>JOIN orders_cte o ON u.id = o.user_id;<

 

이 예제에서는 두 개의 CTE를 생성합니다. user_cte에서는 사용자 정보를 가져오고, orders_cte에서는 주문 정보를 가져옵니다. 그 다음, 두 CTE를 조인하여 결과를 가져옵니다.

Chatbot개발을 위한 KoAlpaca

Alpaca는 Facebook에서 공개한 LLama 모델을 스탠포드에서 개량한 것입니다.

Alpaca에 한국어 학습데이터를 추가한 것이 KoAlpaca입니다.

GPT API가 과금 문제가 있고 제차 빌드를 하려면 비용이 많이 들기 때문에 KoAlpaca의 공개된 엔진을 사용해서 어설픈 챗봇을 만들기로 했었습니다.

하지만 아래와 같은 이유로 포기했습니다.

포기 이유

  • GPU 없이 모델을 로딩해서 인퍼런스(문장완성이나 답변)을 뽑는 것이 너무 느림
  • GPU를 사용하려면 3080ti 같은 PC급 GPU로는 가장 가벼운 모델도 로딩하기 어려움
  • 원할한 서빙을 위해서 A100 이상의 GPU로 서빙을 해야 하는데 비용이 높음
  • KoAlpaca의 품질이 GPT 3.5에 비해서도 확인히 떨어짐. 한국어는 매우 심함

현실적으로 챗봇의 품질을 확보하려면 GPT API를 사용하거나 Azure를 사용하는 것이 가장 품질과 비용을 고려한 솔루션이 될 것 같습니다.

KoAlpaca는 누군가 모델을 더 개선할 때까지 기다려야 할지 모르겠네요.

Bigquery를 이용한 시퀀스(Sequence)데이터 처리 방법

시퀀스 데이터 프로세싱은 다음과 같은 문제가 있습니다.

  1. window function은 where와 같은 조건을 지정해서 프레임내에 로우를 선택할 수 없습니다. 지원하는 경우도 있지만 드뭅니다.
  2. 시퀀스 데이터프로세싱은 매우 중요하지만 분산처리를 하기 매우 어렵기 때문에 처리 속도가 느리거나 정합성을 일부 포기해야 하는 문제가 있습니다.
  3. 시퀀스 데이터프로세싱은 미래에 결정된 데이터에 따라 과거의 데이터를 업데이트하는 것이 매우 어렵거나 되지 않습니다. (Google DataFlow와 같은 것은 가능)

기억해야 할 것

  • 윈도 펑션의 안과 바깥의 구분
    • “윈도 펑션의 결과값은 결국 1개의 값”
  • 특정 그룹의 시퀀스 토큰별로 그룹만들기
  • 값의 변화에 대한 기록 방법
  • 특정 프레임의 조건을 만드는 트릭
  • 태깅값에 의한 집계

예제 준비중

대학 전공서적, 기술서적 무료 다운로드 사이트 및 기타

LibGen(Library Gernesis)이라는 사이트에서 받으면 됩니다.

러시아 사이트인 것 같습니다.

https://libgen.is/

Z=library도 유명합니다.

https://z-lib.is/

논문 받는 곳은 다들 아시는

https://sci-hub.se/

그리고 논문의 Impact를 알아보는 Journal Impact Search 입니다.

https://www.bioxbio.com/

저널의 랭킹을 보는 곳은 SJR

https://www.scimagojr.com/journalrank.php

PySpark lit 메쏘드

pyspark에서 .lit()는 문자열의 값을 모두 채워서 컬럼으로 만들어주는 메소드입니다.

다음과 같이 사용합니다.

import pyspark
from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('SparkByExamples.com').getOrCreate()
data = [("111",50000),("222",60000),("333",40000)]
columns= ["EmpId","Salary"]
df = spark.createDataFrame(data = data, schema = columns)

더 자세한 것은 아래의 블로그를 참고하세요.

https://cosmosproject.tistory.com/291

ls: cannot open directory .: Stale file handle

ls: cannot open directory .: Stale file handle

Linux에서 파일 목록을 확인하다가 위와 같은 오류가 보일 때가 있습니다.

원인

  • NFS(네트워크 스토리지)가 순간적으로 접속이 끊겼거나 마운트가 해제되었을 때
  • ls 하는 디렉토리가 삭제된 경우

해결책은 마운트를 점검하거나 다른디렉토리로 이동한 후 다시 해보면 되는 것이 전부입니다.

Python으로 Click Prediction 모델 만들기

Click Prediction 모델 만들기

Click Prediction 모델은 사용자가 클릭할 가능성이 높은 광고를 예측하는 기계학습 모델을 말합니다.

광고 뿐만 아니라 쇼핑몰의 상품배열이나 노출, 검색 결과의 노출 여부나 랭킹에서도 많이 쓰입니다.

네이버쇼핑, 쿠팡 같은 이커머스(e-commerce)에서도 매우 중요하게 쓰이는 기계학습 콤포넌트입니다.

Python을 사용하여 Click Prediction 모델을 만드는 간단한 예제입니다.

데이터 불러오기

Click Prediction 모델을 만들기 위해서는 먼저 데이터를 불러와야 합니다. 이번 예제에서는 Kaggle에서 제공하는 Click Prediction 데이터를 사용하겠습니다. 데이터는 다음과 같은 링크에서 다운로드할 수 있습니다: https://www.kaggle.com/c/avazu-ctr-prediction/data.

import pandas as pd

data = pd.read_csv('train.csv', nrows=100000)

여기서 train.csv는 데이터 파일의 경로를 의미합니다. nrows 파라미터를 사용하여 데이터의 일부분만 불러올 수 있습니다.

데이터 전처리

모델을 만들기 위해서는 데이터를 전처리해야 합니다. 이번 예제에서는 데이터에서 필요한 feature만 추출하고, 범주형 변수를 One-Hot Encoding하는 것으로 전처리를 마칩니다.

features = ['C1', 'banner_pos', 'site_category', 'app_category', 'device_type', 'device_conn_type']
data = pd.get_dummies(data[features])

데이터에서 features에 해당하는 feature만 추출하고, pd.get_dummies() 함수를 사용하여 범주형 변수를 One-Hot Encoding합니다.

모델 학습

전처리된 데이터를 기반으로 모델을 학습합니다. 이번 예제에서는 LightGBM이라는 머신러닝 라이브러리를 사용하여 모델을 학습합니다.

import lightgbm as lgb

X = data.drop('click', axis=1)
y = data['click']

train_data = lgb.Dataset(X, label=y)

params = {
    'objective': 'binary',
    'metric': 'auc',
    'boosting_type': 'gbdt',
}

model = lgb.train(params, train_data, num_boost_round=100)

전처리된 데이터에서 click feature를 제외한 나머지 feature를 X에 저장하고, click feature를 y에 저장합니다. 그리고 lgb.Dataset() 함수를 사용하여 학습 데이터를 생성합니다. 생성된 학습 데이터를 기반으로 모델을 학습합니다.

모델 평가

학습된 모델을 평가합니다. 이번 예제에서는 AUC(Area Under the Curve)를 사용하여 모델을 평가합니다.

from sklearn.metrics import roc_auc_score

y_pred = model.predict(X)
roc_auc_score(y, y_pred)

AUC가 높을수록 모델의 성능이 좋다는 것을 의미합니다.

모델 예측

학습된 모델을 사용하여 Click Prediction을 수행합니다.

test_data = pd.read_csv('test.csv')
test_data = pd.get_dummies(test_data[features])

y_pred = model.predict(test_data)

test.csv 파일을 불러와서 전처리를 한 후, 학습된 모델로 Click Prediction을 수행합니다.

이상으로 Python을 사용하여 Click Prediction 모델을 만드는 예제를 마치겠습니다.

이 예제를 참고하여, 다양한 Click Prediction 만들어 볼 수 있겠습니다.

그리고, 이 예제에서는 LightGBM 라이브러리를 사용하여 모델을 학습하였지만, 다른 머신러닝 라이브러리 또한 사용할 수 있습니다. 이를 통해, 다양한 머신러닝 라이브러리를 비교하여 어떤 라이브러리가 Click Prediction 모델에 더 적합한지 알아볼 수 있습니다.

매크로 평균(Macro-average)과 마이크로 평균(Micro-average)

머신 러닝 분야에서 평가 지표는 모델이 얼마나 잘 동작하는지를 측정하는 데 중요한 역할을 합니다. 이 중에서도 다중 클래스 분류 문제에서는 클래스별 성능을 평가하는 데 있어서 다양한 방법들이 있습니다. 그 중에서도 대표적으로 사용되는 방법으로는 Macro-average와 Micro-average가 있습니다.

Macro-average 매크로 평균

Macro-average는 클래스별 성능 지표를 각각 계산한 후 평균을 내는 방식입니다. 이 방법은 클래스별 데이터 셋이 균등하게 분포되어 있을 때 적합합니다. 예를 들어, 10개의 클래스가 있는 다중 클래스 분류 문제에서 5개의 클래스는 100개의 데이터를 가지고 있고, 나머지 5개의 클래스는 10개의 데이터만 가지고 있다고 가정해 봅시다. 이 경우, Macro-average는 모든 클래스의 성능을 동일하게 취급하므로, 각 클래스의 데이터 수에 관계 없이 모든 클래스가 동일한 비중으로 반영됩니다.

다음은 Macro-average를 계산하는 과정입니다. 클래스 개수가 k개라고 할 때,

  1. 클래스별로 TP(True Positive), FP(False Positive), FN(False Negative), TN(True Negative)를 계산합니다.
  2. Precision, Recall, F1-score 등 성능 지표를 클래스별로 계산합니다.
  3. 클래스별로 계산된 지표들을 모두 더한 후 클래스 수(k)로 나눕니다.

Micro-average 마이크로 평균

Micro-average는 클래스별로 성능 지표를 계산하기 전에 모든 클래스를 하나의 클래스로 간주하고 전체적인 성능 지표를 계산합니다. 이 방법은 클래스별 데이터 수가 다르더라도 모든 클래스의 성능을 동일하게 고려하므로, 클래스별 데이터 수가 차이가 많이 나는 문제에서 유용합니다.

다음은 Micro-average를 계산하는 과정입니다.

  1. 전체 데이터셋에서 TP, FP, FN, TN을 계산합니다.
  2. Precision, Recall, F1-score 등 성능 지표를 전체 데이터셋에 대해 계산합니다.

이제 간단한 예시를 들어보겠습니다. 다음과 같은 3개의 클래스(0, 1, 2)가 있고, 각각의 클래스에 대해 TP, FP, FN, TN의 개수가 다음과 같다고 가정해 봅시다.

클래스TPFPFNTN
0102385
1154781
281494

이 경우, Macro-average와 Micro-average를 각각 계산해 보겠습니다.

Macro-average 계산

  1. 클래스별 TP, FP, FN, TN 계산
클래스TPFPFNTN
0102385
1154781
281494
  1. 클래스별 Precision, Recall, F1-score 계산
클래스PrecisionRecallF1-score
00.83330.76920.8000
10.78950.68180.7317
20.88890.66670.7619
  1. 모든 클래스의 지표를 더한 후 클래스 수로 나눔

$$ \text{Macro-average Recall} = \frac{0.7692+0.6818+0.6667}{3} = 0.706 \\\\ \text{Macro-average F1-score} = \frac{0.8000+0.7317+0.7619}{3} = 0.764 $$

Micro-average 계산

1. 전체 데이터셋에서 TP, FP, FN, TN 계산

전체 데이터셋TPFPFNTN
33714260

2. 전체 데이터셋에서 Precision, Recall, F1-score 계산

$$ \text{Micro-average Precision} = \frac{33}{33+7} = 0.825 \\\\ \text{Micro-average Recall} = \frac{33}{33+14} = 0.702 \\\\ \text{Micro-average F1-score} = 2 \times \frac{0.825 \times 0.702}{0.825 + 0.702} = 0.759 $$

이처럼 average Micro-average는 다중 클래스 분류 문제에서 클래스별 성능을 평가하는 데 사용되는 방법 중 두 가지입니다. Macro-average는 클래스별 데이터셋이 균등하게 분포되어 있을 때 유용하며, Micro-average는 클래스별 데이터 수가 차이가 많이 나는 문제에서 유용합니다.

계산 법의 선택

어떤 방법을 선택할지는 데이터셋의 특성에 따라 달라질 수 있습니다.

예를 들어, 클래스별로 데이터 수가 크게 차이가 나지 않고 균등하게 분포된 경우에는 Macro-average를 사용하는 것이 적절할 수 있습니다.

반면에 클래스별로 데이터 수가 크게 차이가 나는 경우에는 Micro-average가 더 적절할 수 있습니다.

클래스별로 데이터가 균등한지 아닌지는 카이제곱검정을 하면 알 수 있습니다.

또한, Macro-average는 클래스별 성능을 독립적으로 평가하기 때문에, 각 클래스가 동등하게 중요한 경우에 적합합니다. 반면에 Micro-average는 모든 클래스가 동일한 중요도를 가지는 것이 아니라, 전체적인 성능이 중요한 경우에 적합합니다.

마지막으로, Macro-average와 Micro-average는 모델의 성능을 평가하기 위해 단독으로 사용하기 보다는, 다른 지표와 함께 사용하는 것이 좋습니다. 또한, 클래스별로 데이터 수가 매우 작거나 없는 경우에는 이를 해결하기 위해 Weighted average 방법을 사용하기도 합니다. 이는 클래스별 데이터 수를 고려하여 평균을 계산하는 방법으로, Macro-average와 Micro-average의 중간 형태라고 볼 수 있습니다. 이러한 방법들을 적절히 사용하여 다중 클래스 분류 모델의 성능을 정확하게 평가할 수 있습니다.

round, ceil, floor, truncate의 차이

숫자를 다룰 때 가장 많이 사용하는 함수 들은 “floor”, “truncate”, “ceil”, “round”입니다. 이 함수들은 수학적인 개념을 기반으로 하고 있으며, 숫자를 다룰 때 유용하게 사용됩니다. 이번 포스트에서는 “floor”, “truncate”, “ceil”, “round” 함수의 차이점과 각각의 사용 예시에 대해 살펴보겠습니다.

floor 함수

“floor” 함수는 입력된 숫자보다 작거나 같은 가장 큰 정수를 반환합니다. 예를 들어, 3.14의 floor 값은 3이 됩니다.

pythonCopy codeimport math

print(math.floor(3.14))  # 3
print(math.floor(-3.14)) # -4

truncate 함수

“truncate” 함수는 입력된 숫자의 소수점 이하를 제거하여 반환합니다. 양수인 경우 “floor” 함수와 같은 결과를 출력하고, 음수인 경우 “ceil” 함수와 같은 결과를 출력합니다. 예를 들어, 3.14의 truncate 값은 3이 됩니다.

import math

def truncate(n, decimals=0):
    multiplier = 10 ** decimals
    return int(n * multiplier) / multiplier

print(truncate(3.14))  # 3.0
print(truncate(-3.14)) # -3.0

ceil 함수

“ceil” 함수는 입력된 숫자보다 크거나 같은 가장 작은 정수를 반환합니다. 예를 들어, 3.14의 ceil 값은 4가 됩니다.

import math

print(math.ceil(3.14))  # 4
print(math.ceil(-3.14)) # -3

round 함수

“round” 함수는 입력된 숫자를 반올림하여 반환합니다. “round” 함수는 두 개의 인수를 받습니다. 첫 번째 인수는 반올림할 숫자이고, 두 번째 인수는 반올림할 자릿수입니다. 예를 들어, 3.14를 소수점 첫째 자리에서 반올림한 값은 3.1이 됩니다.

import math

print(round(3.14))   # 3
print(round(3.75))   # 4
print(round(-3.14))  # -3
print(round(3.141592, 2)) # 3.14

결론

이상으로 “floor”, “truncate”, “ceil”, “round” 함수의 차이점과 사용 예시에 대해 알아보았습니다. 이 함수들은 숫자를 다룰 때 매우 유용하며, 데이터 분석, 수치 계산 등 다양한 분야에서 사용됩니다. 적절한 함수를 사용하여 정확하고 효율적인 작업을 수행할 수 있도록 노력해야 합니다.

파이썬 커맨드라인 어플리케이션 패키지 – Python command-line packages

파이썬 커맨드라인 어플리케이션 패키지

커맨드라인 어플리케이션은 콘솔 어플리케이션 이라고도 합니다. 커맨드라인 어플리케이션은 텍스트 인터페이스로 사용하도록 설계된 컴퓨터 프로그램입니다.  이 그 예입니다. 커맨드라인 어플리케이션은 일반적으로 다양한 인자를 입력값으로 받습니다. 파라미터로 받기도 하고 서브커맨드, 옵션, 플래그, 스위치로도 받습니다.

유명한 커맨드라인 어플리케이션을 모아봤습니다:

  • grep – 평문 데이터 검색 유틸리티
  • curl – URL 구문으로 데이터를 전달하기 위한 도구
  • httpie – 커맨드라인 HTTP 클라이언트로서 cURL보다 사용자 친화적인 대체품
  • Git – 분ㄴ산 버전 컨트롤 시스템
  • Mercurial – 주로 파이썬으로 작성된 분산 버전 컨트롤 시스템

클릭(Click)

click 은 최소한의 코드만으로 커맨드라인 인터페이스를 구성할 수 있도록 해주는 파이썬 패키지입니다. 이 “Command-Line Interface Creation Kit” 은 상세한 설정이 가능하지만 그냥 기본값으로 사용해도 아주 좋습니다.

닥옵트(docopt)

docopt 는 가볍고도 아주 파이썬다운 패키지로서 포직스 스타일의 사용법을 파싱하여 커맨드라인 인터페이스를 직관적이고도 쉽게 만들 수 있게 해주는 라이브러리입니다.

플락(Plac)

Plac 은 파이선 표준 라이브러리 argparse 를 선언형 인터페이스를 사용해 그 복잡성을 숨기는 간단한 랩퍼입니다. 매개변수 파서는 명령형으로 작성할 필요가 없습니다. 그냥 추론됩니다. 이 모듈은 복잡한 걸 원치 않는 사용자, 프로그래머, 시스템 관리자, 과학자 및 일회용 스크립트를 작성하는 대신 커맨드라인 인터페이스를 빠르고 간단하게 개발하고자 하는 사람들을 대상으로합니다.

클리프(Cliff)

Cliff 는 커맨드라인 프로그램을 개발하기 위한 프레임워크입니다. setuptools를 엔트리포인트로 사용하여 서브캐맨드, 출력 포맷터 및 기타 확장을 제공합니다. 이 프레임워크는 svn 과 git 처럼 다단계 명령을 만드는 데 사용됩니다. 여기서 메인 프로그램은 몇 가지 기본적인 인자값 구문 분석을 처리한 다음 서브커맨드를 호출하여 작업을 수행합니다.

시멘트(Cement)

Cement 는 진보된 CLI 어플리케이션 프레임워크입니다. 그 목표는 간단한 커맨드라인 애플리케이션과 복잡한 커맨드라인 어플리케이션 모두를 위한 표준 및 기능이 풍부한 플랫폼을 도입하고 품질 저하없이 신속한 개발 요구 사항을 지원하는 것입니다. 시멘트는 유연하며 그 사용 사례는 간단한 마이크로 프레임워크에서 복잡한 대규모 프레임워크에 이르기까지 다양합니다.

파이썬 파이어(Python Fire)

Python Fire 는 파이썬 객체를 전혀 사용하지 않고도 자동으로 커맨드라인 인터페이스를 생성하는 라이브러리입니다. 커맨드라인에서 파이썬 코드를 보다 쉽게 디버깅하고, 기존 코드에 대한 CLI 인터페이스를 생성하고 REPL에서 인터렉티브하게 코드를 탐색하고, 파이썬과 Bash(아니면 다른 쉘) 간의 전환을 단순화 할 수 있습니다.

아호코라식 Aho-corasick

Ahocorasick은 1975년에 Alfred V. Aho와 Margaret J. Corasick이 고안한 문자열 검색 알고리즘입니다.

입력 텍스트 내에서 유한한 문자열 집합(사전)의 요소를 찾는 사전 매칭 알고리즘의 한 종류로, 모든 문자열을 동시에 매칭합니다.

좀 쉽게 말하면 입력한 긴 문자열에서 찾아냈으면 하는 문자열이 있다면 모두 빠르게 찾아주는 알고리즘입니다.

찾아야 하는 문자열은 미리 정해야 하고 수십만개에서 수백만까지도 쓸 수 있습니다.

Aho-Corasick 알고리즘은 Trie 자료구조를 기반으로합니다. Trie 자료구조는 문자열 검색에 효과적인 자료구조이지만, 문자열 검색이 일어날 때마다 트리를 전부 탐색해야 하는 단점이 있습니다. Aho-Corasick 알고리즘은 이러한 단점을 보완하기 위해, Trie 자료구조를 미리 전처리하여 특정 문자열 집합에서 상호작용하는 부분을 최적화합니다.

Aho-Corasick 알고리즘은 다음과 같은 단계를 거쳐 작동합니다.

  1. 문자열 집합을 Trie 자료구조로 변환합니다.
  2. Trie 자료구조를 이용하여 Failure 함수를 생성합니다. Failure 함수는 각 Trie 노드에서 어떤 문자가 올 때 다음으로 이동해야 할 노드를 결정합니다.
  3. 문자열 검색을 위해 Aho-Corasick 알고리즘은 주어진 문자열을 탐색하면서, Trie 자료구조를 탐색합니다. Failure 함수를 이용하여 검색을 가속화합니다.

Aho-Corasick 알고리즘은 문자열 검색에 효율적이며, 자연어 처리, 네트워크 보안, DNA 염기서열 검색 등 다양한 분야에서 활용됩니다.

Aho-coriaskc은 다중 패턴 매칭(Multiple Pattern Matching)을 해결할 수 있는 방법 중 하나입니다.

하나 이상의 패턴 문자열을 동시에 검색하는 것을 다중 패턴 매칭이라고 하는데 대부분의 문자열 처리 분야에서 매우 중요한 문제 중 하나입니다.

예를 들어, 특정 문자열에서 여러 개의 단어를 찾는 작업을 수행하려면, 이 문자열에서 각 단어를 개별적으로 검색하는 것보다 모든 단어를 한 번에 검색하는 것이 효율적입니다. 이를 위해 다중 패턴 매칭 알고리즘을 사용할 수 있습니다.

다중 패턴 매칭 알고리즘에는 여러 가지 방법이 있는데 대표적인 알고리즘으로는 Aho-Corasick, Rabin-Karp, Boyer-Moore 등이 있습니다. 이들 알고리즘은 각각의 특성과 장단점을 가지고 있으며, 특정한 상황에 맞는 알고리즘을 선택해 쓰는 것이 좋습니다.

참고자료

Python FastAPI

Python의 FastAPI에 대한 소개입니다.

FastAPI는 Python 3.6 이상으로 API를 빌드하기 위한 최신 고성능 웹 프레임워크입니다. FastAPI는 파이썬 표준 타입 힌트를 기반으로 하여 자동 문서화, 데이터 검증, 비동기 지원 등의 기능을 제공합니다.

FastAPI는 Flask나 Django와 같은 다른 웹 프레임워크보다 개발 속도가 200%~300% 빨라진다고 주장합니다. 또한 Node.js나 Go와 비슷한 수준의 성능을 자랑합니다.

FastAPI를 사용하려면 먼저 fastapi 모듈과 uvicorn 서버를 설치해야 합니다3.

pip install fastapi
pip install uvicorn

그 다음, app 객체를 생성하고 app.get 데코레이터를 사용하여 URL과 함수를 연결할 수 있습니다. 예를 들어, ‘/’ URL에 접속하면 ‘Hello World’라는 텍스트를 반환하는 함수를 정의할 수 있습니다.

from fastapi import FastAPI

app = FastAPI()

@app.get('/')
def hello_world():
    return 'Hello World'

마지막으로, uvicorn 명령어로 웹 서버를 실행할 수 있습니다. 이때 포트 번호나 리로드 옵션 등을 설정할 수 있습니다.

uvicorn main:app --reload --port 9999

이렇게 하면 간단한 FastAPI 예제 코드가 완성됩니다. 이 코드는 9999번 포트에서 실행되며, 브라우저에서 http://localhost:9999/ 에 접속하면 ‘Hello World’라는 텍스트가 나타납니다.

SQL의 DDL, DML, DCL

SQL의 DDL, DML, DCL에 대한 간략한 설명입니다.

SQL은 Structured Query Language의 약자로, 데이터베이스에서 데이터를 정의하고 조작하고 제어하는 데 사용하는 언어입니다. SQL은 크게 다음과 같은 세 가지 종류로 나눌 수 있습니다.

  • DDL(Data Definition Language): 데이터베이스나 테이블 등의 객체를 생성하거나 변경하거나 삭제하는 데 사용합니다. CREATE, ALTER, DROP, TRUNCATE 등이 있습니다.
  • DML(Data Manipulation Language): 테이블에 저장된 데이터를 조회하거나 삽입하거나 수정하거나 삭제하는 데 사용합니다. SELECT, INSERT, UPDATE, DELETE 등이 있습니다.
  • DCL(Data Control Language): 데이터베이스에 접근하거나 객체를 사용할 수 있는 권한을 부여하거나 취소하는 데 사용합니다. GRANT, REVOKE 등이 있습니다.

예제 코드는 다음과 같습니다.

-- DDL 예제
CREATE TABLE student ( -- 테이블 생성
    id INT PRIMARY KEY,
    name VARCHAR(20),
    major VARCHAR(20)
);

ALTER TABLE student ADD phone VARCHAR(15); -- 테이블 변경

DROP TABLE student; -- 테이블 삭제

TRUNCATE TABLE student; -- 테이블 내용 삭제

-- DML 예제
SELECT * FROM student; -- 테이블 조회

INSERT INTO student VALUES (1, 'Kim', 'Computer Science', '010-1234-5678'); -- 테이블 삽입

UPDATE student SET phone = '010-8765-4321' WHERE id = 1; -- 테이블 수정

DELETE FROM student WHERE id = 1; -- 테이블 삭제

-- DCL 예제
GRANT SELECT ON student TO user1; -- user1에게 student 테이블 조회 권한 부여

REVOKE SELECT ON student FROM user1; -- user1에게서 student 테이블 조회 권한 취소

Python MySQL warning – Data truncated for column

Python MySQL을 쓰다가 다음과 같은 에러를 만날 때가 있습니다. Pandas의 데이터를 MySQL 테이블 넣거나 할 때 생기는 문제입니다. 경고이기 때문에 큰 문제는 없지만 경고 메세지를 화실하게 해결하고 싶을 때가 있습니다.

Data truncated for column ~

다음과 같이 해결하면 됩니다.

해결책

  • VARCHAR인 경우에는길이를 늘려준다.
  • Numeric이면 소숫점이 몇자리까지 허용인지 보고 미리 round 처리해준다.

비용 이상감지 – Cost Anomaly Detection

비용이상감지

비용 이상감지는 이상감지를 비용과 밀접한 관련이 있는 데이터에 하는 것입니다.

이상감지는 시간에 따른 흐름과 추세의 패턴이 있는 시계열 데이터가 과거의 패턴에서 많이 벗어났는지를 감지하는 모델을 말합니다.

이상감지는 통계적 모델, 기계학습, AI 등 모든 종류의 모델을 다 사용합니다.

이상감지는 주로 사고를 미리 감지하기 위한 것이 많은데 온라인 서비스의 다운 징후, 온라인 서비스 사용자 또는 트래픽의 급증과 급감, 각종 공장 또는 장치의 사고나 고장 위험 등을 위해서 모델을 만들고 운영합니다.

BI와 대시보드, 그라파나, 키바나 같은 것에 연동하거나 별도의 시각화를 만들기도 합니다.

이상감지의 세부 갈래 중 하나인 비용이상감지는 사고 중에서도 비용지불에 대한 이상감지에 중점을 둡니다.

전기료, 수도요금, 클라우드서비스 비용 등과 같은 것입니다.

하지만 전기료, 수도요금은 실시간으로 데이터를 추적하기 어렵고 특별히 이상이 발생하기 어렵기 때문에 이상감지가 유용하지 않습니다. 대신 최근에 많이 사용되는 클라우드 비용 관리에는 큰 효과가 있습니다.

클라우드 비용 이상감지

비용이상감지를 사용하면 클라우드 비용의 과다 지출에 대한 사전 징후를 미리 감지해서 비용 낭비를 방지할 수 있습니다. 체크해야 할 항목이 매우 많기 때문에 어떻게 운영하느냐에 따라 다르겠지만 전체 비용에 대해서 비용을 구성하는 모든 하위 지표를 모니터링해서 그중에 문제를 발생시키는 가장 이상한 지표들을 빨리 감지하는 용도로 쓸 수 있습니다.

광고 캠페인의 비용 이상감지

그외에 광고 캠페인의 운영에 대한 지출 비용에 대한 이상여부를 감지하는데도 사용할 수 있습니다.

광고 캠페인은 최대 지출 비용을 정해두고 사용하는 경우에는 예상했던 기간보다 더 빨리 광고비가 소진되는 것을 발견해서 이상 징후를 감지하고 캠페인 중에 최대 비용을 정하지 않고 신용카드를 등록한 후 집행된 만큼 지불하는 경우에는 매우 유용합니다.

이상감지 – 랜덤컷포레스트 러스트 소스 Random Cut Forest Rust

랜덤컷포레스트 (Random Cut Forest)는 AWS에서 만든 이상감지모델입니다.

감지가 매우 정확한 편이지만 처리 속도가 매우 느린 알고리즘입니다.

랜덤컷포레스트의 Rust소스를 github에서 발굔해서 여겨에 소개합니다.

https://github.com/aws/random-cut-forest-by-aws/tree/main/Rust/src

아직 실행은 해보지 못했습니다.

ChatGPT

ChatGPT

ChatGPT(챗GPT)는 채팅(대화)를 위해 만든 인공지능 소프트웨어입니다.

채팅을 위해 만든 GPT라는 뜻인데

GPT 모델은 인공지능 모델을 한 방식입니다.

건축에 빗대어 얘기하면 인공지능을 만드는 설계방식의 한 종류라고 생각하면 됩니다.

인공지능 모델은 수학적인 구조를 실제로 작동하게 만든 자료와 소프트웨어 덩어리를 말합니다.

즉 컴퓨터 프로그램입니다.

GPT를 만든 곳은 OpenAI(오픈에이아이)라는 비영리연구회사입니다.

이 회사의 초기 투자자로는 테슬라의 일런 머스크가 있고 현재 가장 큰 투자자는 마이크로소프트입니다.

GPT (Generative Pretrained Transformer)

GPT는 생성가능한 선행 학습된 트랜스포머 라는 뜻인데

트랜스포머는 구글이 만든 언어 해석 및 합성을 위한 인공지능모델입니다.

GPT는 구글이 만든 트랜스포머의 변형 및 개량형입니다.

GPT의 장점

실현가능한 초거대언어모델이라는 점이 장점입니다.

초거대모델은 엄청나게 많은 문서자료를 학습해서 그 문서들의 모든 맥락고 의미를 거대한 자료로 압축해 놓은 것을 말합니다.

초거대 모델을 학습하기 위해서 막대한 컴퓨터계산이 필요합니다.

다른 모델들은 이렇게 많은 문서자료를 학습해도 제대로 학습하지 못해서 그리 똑똑하지 않거나 학습하는데 컴퓨터계산이 너무 많이 들어서 100년이 걸려도 학습이 안 끝날 수 있습니다.

GPT는 초거대 모델을 한 번 만드는데 4주 정도 소요되고3 00억 정도의 돈을 쓰는 것으로 알려져 있습니다.

MISCONF Redis is configured to save RDB snapshots, but it’s currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

Redis의 내용물을 저장할 때 발생하는 에러다

메세지가 매우 긴 에러이다.

MISCONF Redis is configured to save RDB snapshots, but it’s currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

해결책은

다음과 같이 해결할 수도 있고

config set stop-writes-on-bgsave-error no

다음과 같이 해결할 수도 있다

CONFIG SET dir /tmp/some/directory/other/than/var
CONFIG SET dbfilename temp.rdb

시계열데이터를 예측할 때 선형회귀(Linear Regression)를 사용하지 않는 이유

시계열 데이터 예측할 때 선형회귀를 안쓰는 이유?

시계열 데이터는 시간의 순서대로 측정된 데이터이기 때문에 시간에 따른 순서가 있습니다. 일반적인 선형 회귀모형인 최소제곱법을 사용할 경우, 예측값과 실제값의 차이를 제곱한 값을 최소화하는 것이 목표입니다. 이러한 최소제곱법은 잔차의 분포가 정규분포를 이루는 경우에만 적용됩니다. 시계열 데이터의 경우 잔차의 분포가 정규분포를 이루지 않을 수 있기 때문에 최소제곱법을 적용할 수 없습니다.

그렇기 때문에 시계열 데이터에서는 최소제곱법을 사용하는 선형 회귀모형 대신에, 잔차의 분포가 정규분포를 이루지 않더라도 적용할 수 있는 모형을 사용합니다. 이러한 모형에는 시계열 잔차의 자기상관계수가 일정한 수준 이하인 자기상관 선형 모형 (ARIMA), 시계열 잔차가 정규분포를 이루지 않는 경우에 적용할 수 있는 시계열 잔차의 분포가 일정한 수준 이하인 자기상관 선형 모형(ARIMAX) 등이 있습니다.

또한, 시계열 데이터의 경우 자기상관이 있을 수 있기 때문에 일반적인 선형 회귀모형과는 달리 자기상관을 제거하기 위해 차분(differencing) 작업을 수행할 수 있습니다. 차분은 시계열 데이터의 차이값(difference)을 사용하여 자기상관을 제거하는 과정입니다. 이렇게 차분한 시계열 데이터에 선형 회귀모형을 적용할 수 있습니다.

시계열 데이터에 선형 회귀모형을 적용하지 않을 수도 있습니다. 이 경우 시계열 데이터의 특성을 잘 반영할 수 있는 모형을 선택해야 합니다. 예를 들어, 시계열 데이터가 점선으로 그려지고 추세가 있는 경우 선형 회귀모형이 적합하지 않을 수 있습니다. 이 경우에는 추세를 반영할 수 있는 적절한 모형을 선택할 수 있습니다. 예를 들어 추세가 있는 시계열 데이터에는 추세를 고려한 선형 회귀모형인 전방산정모형(forward-looking regression model)과 지수선형회귀모형(exponential linear regression model) 등이 적용될 수 있습니다.

또한, 시계열 데이터의 경우 시간에 따른 추이가 있을 수 있기 때문에 시간에 따른 추이를 반영할 수 있는 모형도 적용할 수 있습니다. 예를 들어 시계열 데이터의 경우 시간에 따른 추이가 있고, 이를 선형으로 나타낼 수 없을 경우에는 시간에 따른 추이를 나타낼 수 있는 시계열 모형인 선형 추이선형회귀모형(linear trend linear regression model)과 지수선형 추이선형회귀모형(exponential trend linear regression model) 등이 적용될 수 있습니다.

정리하자면, 시계열 데이터에는 선형 회귀모형을 적용하기 어려울 수 있는 여러가지 이유가 있습니다. 시계열 데이터의 경우 잔차의 분포가 정규분포를 이루지 않을 수 있기 때문에 최소제곱법을 적용할 수 없기 때문입니다. 또한, 시계열 데이터는 자기상관이 있을 수 있기 때문에 차분을 통해 자기상관을 제거할 수 있습니다. 이 경우 차분한 시계열 데이터에 선형 회귀모형을 적용할 수 있습니다. 또한, 시계열 데이터의 경우 추세가 있거나 시간에 따른 추이가 있을 수 있기 때문에 이를 반영할 수 있는 모형을 적용할 수도 있습니다.

데이터베이스의 현재 타임존 확인하는 방법 – How to get current timezone on MySQL database

데이터를 다룰 때 날짜 타입이 있는 경우에는 타임존을 항상 신경써야 합니다.
어떤 날짜타입은 타임존을 내부에 가지고 있고 어떤 타입은 그렇지 않습니다.
데이터를 추가할 때 현재 날짜 또는 시각의 타임스탬프를 자동으로 추가하는 기능을 사용할 때는 어떤 타임존으로 설정되어 있는지 확인하고 사용해야 합니다.

# getting current timezone of database system
SELECT @@global.time_zone, @@session.time_zone;

# checking difference default timezone with UTC 
SELECT TIMEDIFF(NOW(), CONVERT_TZ(NOW(), @@session.time_zone, '+00:00'));

# example code for converting timezone
SELECT CONVERT_TZ(CURRENT_TIMESTAMP, '+09:00', '+00:00');

MySQL 데이터베이스 타임존 확인 하는 법

타임존(timezone) 문제는 항상 골치가 아픕니다.

특히 데이터와 관련된 문제에서는 더욱 더 그렇고, 돈과 관련된 데이터라면 더더욱 문제가 딥니다.

MySQL, MariaDB에서 현재 시스템의 타임존을 확인하는 방법입니다.

# 시스템 설정 확인하기
SELECT @@global.time_zone, @@session.time_zone;
# 실제 GMT와의 시간차이 확인하기
SELECT TIMEDIFF(NOW(), CONVERT_TZ(NOW(), @@session.time_zone, '+00:00'));
# tz 바꾸는 코드 테스트
SELECT CONVERT_TZ(CURRENT_TIMESTAMP, '+09:00', '+00:00');

신기한 Copilot 사용예 – 날짜목록 자동생성

오늘이 공휴일인지 아닌지 확인하는 간단한 코드를 Python으로 작성하는 것인데

이 예제에서 신기한 것은 Copilot이 주석의 내용을 보고 코드에 데이터를 자동으로 추가해주는 기능도 있다는 것입니다.

공휴일 날짜 데이터가 문제입니다.

자동으로 코드내에 공휴일데이터를 추가하는 방법을 알려드립니다.

아래 사이트에 접속해서 공휴일에 대한 정보를 복사합니다.

https://publicholidays.co.kr/ko/2023-dates/

Copilot이 설치된 vscode를 실행하고 코딩을 준비합니다.

아래의 코드에서 상단에 있는 것이 위의 사이트에서 복사해서 붙여넣은 데이터입니다.

복사한 후에 주석처리를 해놓고 밑에서 코드를 입력해서 완료하면 되는데

밑에 holiday_list = [ 라고 입력하고 Copilot의 추천을 기다리면 주석의 내용을 파악해서 공휴일에 해당하는 모든 데이터를 한 번에 또는 부분적으로 모두 완성해 줍니다.

여기서 신기한 것은 9월 28일 ~ 9월 30일과 같이 구간으로 표현된 것도 인지하고 날짜 목록에 나열해서 넣어 준다는 것입니다.

# 2023년 대한민국 공휴일
# 날짜	요일	공휴일
# 1월 1일	일요일	새해
# 1월 21일 ~ 1월 24일	토요일 ~ 화요일	설날
# 3월 1일	수요일	3·1 운동/삼일절
# 5월 5일	금요일	어린이날
# 5월 27일	토요일	부처님 오신 날
# 6월 6일	화요일	현충일
# 8월 15일	화요일	광복절
# 9월 28일 ~ 9월 30일	목요일 ~ 토요일	추석
# 10월 3일	화요일	개천절
# 10월 9일	월요일	한글날
# 12월 25일	월요일	크리스마스

# check if today is holiday or not
holiday_list = [
    '2023-01-01', '2023-01-21', '2023-01-22', '2023-01-23', '2023-01-24',
    '2023-03-01', '2023-05-05', '2023-05-27', '2023-06-06', '2023-08-15',
    '2023-09-28', '2023-09-29', '2023-09-30', '2023-10-03', '2023-10-09',
    '2023-12-25'
]

today = datetime.datetime.today().strftime('%Y-%m-%d')
if today in holiday_list:
    print('Today is holiday')
else:
    print('Today is not holiday')

딥러닝 초보를 위한 쉬운 설명 – Deep learning

딥러닝 (Deep Learning)의 쉬운 이해

딥러닝은 “깊은 학습”이라는 뜻이고 “심화학습”이라고 번역합니다만 원래 뜻과는 잘 안맞고 멋이 없어서 그냥 “딥러닝”이라고 부릅니다.

딥러닝은 신경망(뉴럴 네트워크, Neural Network)이라고 하는 인공지능 구현 방식이 있는데 그 것의개량형입니다.

딥러닝은 신경망의 다른 별명이고 개량된 신경망을 뜻하는 단어입니다.

그래서 딥러닝을 이해하려면 신경망에 대해서 무조건 알아야 합니다.

신경망은 인간의 뇌구조를 모방해서 만든 인공지능을 만들기 위한 설계 구조이자 방식입니다.

신경망은 아주 예전에는 전기, 전자회로로 구현했고 요즘은 다 컴퓨터 소프트웨어로 구현합니다.

신경망을 개량하기 위해서 직접 만들기도 하고 기조의 구조를 고쳐서 인공지능 모델을 만들기도 합니다.

그래서 프로그래밍을 하긴하지만 프로그래밍 양은 많지 않고 만들어진 소프트웨어 골격을 재배열하고 데이터를 가공하거나 변환해서 넣고 결과를 확인하기 위한 것이 대부분입니다.

어쨌든 인공지능을 만들기 위한 절차의 집합입니다.

딥러닝과 일반 신경망의 차이

딥러닝과 일반 신경망의 차이는 딥러닝이 신경망의 구조에서 망 내의 신경 층들 수가 더 많고 길게 할 수 있다는 차이가 있습니다.

신경망이 깊으면 더 정교한 판단을 하는 인공지능을 만들 수 있습니다.

그럼 딥러닝이 나오기 전에는 깊은 구조 (복잡한 구조)의 신경망을 못 만들었다는 말인가? 라고 셩각하실텐데 그렇습니다.

딥러닝 이전에도 깊은 구조의 신경망을 만들 수는 있었지만 만들어진 신경망이 멍텅구리가 되기 때문에 결과적으로는 만들 수 없었습니다.

깊은 구조의 신경망을 만들 수 없었던 이유는 미분 때문

많은 이유가 있지만 가장 큰 이유는 미분으로 인한 문제입니다.

신경망에서 미분은 크게 2가지 문제를 만듭니다.

GPGPU로 대량의 계산을 더 빨리 처리하게 됨

신경망은 파라미터 최적화라는 작업을 합니다.

파라미터 최적화는 신경망 내에 있는 숫자값들을 학습데이터에 맞게 조금씨 고쳐서 바꿔가는 작업입니다.

파라미터 최적화를 위해서 대수학에서 하는 미분을 해야하는데 아주 많이해야 합니다.

미분을 많이해야 하면 계산할 것이 많아져서 컴퓨터가 힘이듭니다.

이건 이런 종류녜 단순 계산을 한 번에 많이 할 수 있는 GPGPU의 발전으로 해결되었습니다.

그래디언트 소실 문제 해결

그 다음은 미분이 반복되면서 파라미터의 숫자값들이 모두 0에 점점 가까워지는 문제를 해결했습니다.

이 문제를 그래디언트 배니싱이라고 부릅니다.

파라미터가 모두 0이 되거나 0에 가까우면 인공지능이 바보가 되는데 그 이유는 신경망의 층이 매우 많을 때 미분이 반복되기 때문입니다.

0이 가까워지는 이유는 미분의 대상이 되는 함수인 시그모이드라는 신경망에서 애용했던 함수의 특성때문입니다. 딥러닝에서는 이 함수를 렐루(ReLU)라는 미분해도 숫자가 계속 작아지지 않는 함수로 바꿔서 해결합니다.

알고보면 엄청 간단하지만 해결하는데 엄청나게 오랜 시간이 걸린 것입니다.

딥러닝 책과 자료는 서점과 온라인에 많이 있습니다. 자세한 자료는 그걸 참조하세요.

Selenium Grid 셀레니엄 그리드

셀레니엄(Selenium)은 웹서비스를 테스트하기 위해 사용하는 오래된 자동화도구입니다.

웹서비스를 테스트하기 위해서는 웹브라우저를 사람대신 작동하게 해서 접속하고 클릭하고 페이지를 이동하는 등의 작동을 시키고 결과를 본 후에 제대로 작동하는지 측정합니다.

이걸 위해서 필수적으로 3가지가 필요합니다.

  • 웹브라우저
  • 웹브라우저를 자동으로 핸들링하는 웹드라이버
  • 웹드라이버를 핸들링하기 위한 컴퓨터언어와 패키지

셀레니엄은 위에서 3번째것을 지원합니다.

웹브라우저와 웹드라이버는 웹브라우저를 만드는 곳에서 제공합니다.

셀레니엄의 용도

웹서비스가 제대로 작동하는지 화인하는데 씁니다.

데이터를 크롤할 때 씁니다.

데이터클 크롤할 때 셀레니엄을 쓰는 이유는 Javascript를 사용해서 동적으로 콘텐츠를 디스플레이하는 사이트때문입니다.

이런 사이트의 데이터를 크롤하려면 접속하는 웹클라이언트에 자바스크립트를 구동시키고 화면을 렌더링할 수 있는 엔진이 있어야 하는데, 이게 쉽게 만들 수 있는 물건이 아닙니다.

그래서 기존의 웹브라우저를 자동화해서 움직이게해서 테스트 용도로 사용하게 하는 방법이 생겨났는데 그중에 가장 오래되고 유명한 것이 셀레니엄입니다.

그리고 이런 사이트의 데이터를 자동으로 가져가기 위해서 역시 셀레니엄을 쓰게 됩니다.

셀레니엄의 단점

구동하게 하기 위해서 자원을 많이쓰는 웹브라우저를 사용해야합니다.

쉡게 말하면 셀레니엄은 매우 무겁습니다.

셀레니엄의 장점

앞서 말했듯이 셀레니엄을 쓰면 동적 생성되는 콘텐츠를 테스트하거나 크롤할 수 있습니다.

React나 Vue.js 같은 것들로 만들어진 웹페이지에도 쓸 수 있습니다.

셀레니엄 그리드는 뭔가?

  • 셀레니엄을 설치하면 여러가지 이상한 패키지를 서버 또는 랩탑에 설치해야 합니다
  • 그리고 그냥 쓰게 되면 서버의 자원을 순간적으로 많이 쓰게 됩니다.
  • 쓰고나면 찌꺼기 파일을 많이 만들어 놓습니다

그래서 셀레니엄을 여러 서버에 미리 설치해서 클러스터를 만들어놓고 그걸 필요할때 가져다 쓸 수 있습니다.

그런 환경을 만들어 주는 것을 셀레니엄 그리드입니다.

아래 사이트에서 설치법을 볼 수 있습니다. 비교적 쉽습니다.

https://www.selenium.dev/documentation/grid/

그리고 셀레니엄 서버라는 것이 예전에 존재했었는데 그 후속으로 나온 버전이 셀레니엄 그리드입니다.

셀레니엄 그리드의 장점

  • 차원이 더 필요할 때 수평 확장이 쉽습니다.
  • 자원을 효율적으로 사용할 수 있습니다.
    • 여러 서버가 셀레니엄 그리드 클러스터로 부터 필요할 때 자원을 가져다 쓰기 때문입니다

Last Touch Attribution, LTA 모델

Last Touch Attribution은 광고 마케팅에서 사용하는 용어입니다.

데이터 기술로는 애드테크(Ad tech), 마테크(MarTech)에서 볼 수 있는 용어입니다.

번역할 수 있는 적당한 한국말이 아직 없어 그냥 “라스트 터치 애트리뷰션”이라고 부릅니다.

Last Touch Attribution이란?

간단하게 설명하면

광고주가 여러 광고매체에 광고를 했는데 고객이 전환을 만들었을 때 한 고객이 여러 매체를 통해 들어왔더라고 전환이 발생하기 직전인 가장 마지막에 고객이 접촉한 매체(광고수단)에만 그 기여를 인정하겠다는 것을 말합니다.

자세히 설명하면

짧고 작게 볼 때 광고의 목적은 전환을 발생시키는데 있습니다. 크게 보면 회사의 매출을 올리는데 있고 비즈니스를 성장시키는데 있습니다만.

전환은 구매, 회원가입, 상담신청하기, 앱 설치하기, 사전구매 신청하기 , 구독하기 등과 같은 광고주의 비즈니스에서 매출과 직접 관련이 있거나 광고주가 광고를 통해서 고객으로부터 얻고 싶은 최종 액션을 말합니다.

전환을 발생하기 위해서 어떤 매체가 파급력이 좋을 지, 효율이 좋을지 모르고 또 잠재 고객이 어느 특정 매체에 몰려 있거나 하지 않기 때문에 여러 매체를 통해 광고를 진행합니다.

매체는 구글키워드광고, 구글디스플레이광고, 페이스북광고, 인스타그램광고, 유튜브광고, 이메일, 카카오복 광고 같은 것들을 말합니다.

여러 매체를 통해 여러 캠페인을 진행하면 동일한 제품 또는 제품 카테고리에 대해서 동일한 사람이 여러 매체에서 광고를 보고 각각 클릭을 해서 제품을 살펴보고 구매의사가 있다면 구매를 하게됩니다.

이때 1명의 고객이 여러 매체에서 광고를 모두 보고 클릭을 했지만 구매 직전에 마지막에 클릭한 매체의 기여만 인정하고 나머지는 무시하는 것이 Last Touch Attribution입니다.

이것은 마지막에 클릭한 매체에서 보여졌던 광고가 전환에 가장 큰 영향을 줬다고 그 영향이 결정적이었다고 간주하는 것입니다.

Last Touch Attribution 모델의 문제점

상식적으로 볼 때 이 것은 매체들에게는 매우 불리합니다. 고객이 어느 시점에 물건을 살지를 알아서 그 직전에 광고를 보여주고 클릭하도록 만들어야 하는데 쉬운 것이 아닙니다. 그리고 앞서 발생햏던 모든 클력을 무효로하고 마지막 클릭만 전환에 기여했다는 것은 상식적으로도 말이 되지 않습니다.

Last Touch Attribution 모델을 쓰는 이유

광고생태계에서는 대부분의 MMP(Mobile Measurement Partner, 모바일 앱에서 광고 성과를 추적해주는 서비스)나 GA등은 이 모델은 기본으로 기여도를 산출하고 있고 광고주들도 이 모델은 기본으로 하고 있습니다. 물론 다른 기여도 모델도 지원하긴 하지만 기본으로 지원하는 것을 그냥 대부분 쓰기 때문에 다른 모델을 쓰는 경우는 많지 않습니다.

또 다른 이유는 이게 계산하기 편하고 쉽기 때문입니다.

즉 다른 기여도 모델에 비해서 데이터프로세싱에 드는 리소스가 적고 덜 복잡하기 때문입니다. 보통 마케팅을 집행하는 마케팅부서는 IT부서가 아니고 IT지원을 받지 못하거나 받지 않으려고 하는 경향이 강해서 데이터프로세싱을 잘 하지 못합니다. 그래서 비교적 데이터프로세싱이 편한 방법을 쓰거나 기본으로 프로세싱까지 해서 수치를 산출해 주는 Last Touch Attribution을 쓰게 됩니다.

광고주 입장에서는 속 편한 것입니다. 광고주는 갑이고 매체들은 을이기 때문에 광고주가 마지마 터치만 인정하겠다고 선언하면 그뿐입니다. 기여도를 올리고 싶다면 전환직전의 마지막 클릭을 만들면 된다고 말하고 그렇게 하라고 하면 됩니다.

기여도가 낮은 매체는 어떻게 되는가?

기여도가 낮은 매체는 광고 효율이 좋지 않기 때문에 광고주가 광고비를 줄일 때 가장 먼저 광고를 진행하지 않고 빼버리는 대상이 됩니다. 특정 매체의 경우 First Touch가 아주 높다면 그런 매체는 이 모델로 판정하게 되면 기여도가 매우 낮기 때문에 빠지게 됩니다.

그래서 Last Touch를 많이 만들지는 못했지만 First Touch나 Middel touch가 많은 매체는 이 모델이 불공평하다고 주장하고 Last Touch가 좋은 매체는 Last Touch가 가장 좋다고 주장합니다.

업종과 물건에 따라 다른 Last Touch

Last Touch는 업종, 물건의 종류, 물건의 가격대, 구입하는 고객의 구성에 따라 다릅니다. 그렇기 때문에 광고주의 입장에서는 자신들이 판매하는 물건 또는 비즈니스의 특성과 고객군에 대해 제대로 이해하고 있어야 하고 그에 따라 어떤 Touch Model을 쓸지와 어던 매체가 좋은지도 판단해야 합니다.

단순하게 어떤 것이 가장 좋으니 그것만 쓰면 된다고 말할 수눈 없습니다.

필요한 데이터 기술

앞서 말했듯이 last touch attribution은 아주 쉽습니다. 전환 이 전에 가장 마지막에 고객이 타고 들어온 광고매체가 어딘가를 찾아내서 카운트해주면 됩니다.

RDB, 빅데이터플랫폼, 실시간 데이터처리 플랫폼으로도 매우 쉽습니다. 그 외에 통계 기술, 기계학습, AI는 전혀 필요하지 않습니다.

간단하다고는 말하지만 엑셀로 하려면 매우 복잡합니다. 그래서 데이터프로세싱 기술이 전혀 필요 없다고는 할 수 없습니다. 물론 데이터가 아주 많지 않다면 엑셀로 할 수는 있습니다.

Multi Touch Attribution 모델

하지만 최근에는 이 모델이 정말 효율좋은 광고 매체를 골라내지 못한다는 당연한 문제점 때문에 Multi Touch Attribution Model을 사용하는 경우가 늘고 있습니다.

ImportError: cannot import name ‘_psutil_linux’ from partially initialized module ‘psutil’

다음과 같은 에러가 주피터 랩(Jupyter lab)에서 나는 경우가 있습니다.

ImportError: cannot import name ‘_psutil_linux’ from partially initialized module ‘psutil’

패키지 설치가 조금 꼬인 경우입니다.

다음과 같이 패키지를 설치해서 해결할 수 있습니다.

python -m pip install --ignore-installed psutil

ImportError: cannot import name ‘_psutil_linux’ from partially initialized module ‘psutil’ (most likely due to a circular import) (/usr/lib/python3/dist-packages/psutil/init.py)

다음과 같은 에러가 날 때가 있습니다.

ImportError: cannot import name '_psutil_linux' from partially initialized module 'psutil' (most likely due to a circular import) (/usr/lib/python3/dist-packages/psutil/__init__.py)

psutil을 다시 설치해주면 되는데 아마도 이미 설치되어 있다고 나올 것입니다.

다음과 같이 옵션을 주고 설치된 것을 무시하고 재설치하면 됩니다.

python3.8 -m pip install --ignore-installed psutil

모바일 게임에서 모바일 게임 광고가 많이 보이는 이유

게임 광고에 대한 분석을 하다 보면 종종 재밌는 사실을 알 수 있습니다.

그 중에 재밌는 것은 게임 내에서의 게임 광고입니다.

게임 내에 다른 게임 광고

모바일 게임을 설치해서 하다보면 아이템을 얻거나 다시시도를 하는 댓가로 광고를 보게하는 것이 많다. 광고 수익을 얻기 위한 것인데 게임 광고에서는 유난히 다른 게임의 광고가 많이 나옵니다.

이것은 예전에는 카니발라이제이션이라는 문제라 하지 않았던 것입니다. 즉 다른 게임의 광고를하면 사용자가 그 게임을 설치해서 하게 되고 지금 하는 게임은 하지 않기 때문입니다.

하지만 그럼에도 불구하고 최근 게임광고가 게임에 많이 보이는 이유는 다음과 같습니다.

모바일 게임에서 모바일 게임 광고가 많이 나오는 이유

  • 게임은 원래 하던 사람이 하기 때문에
  • 이 사람들은 하던 게임이 지루하면 새 게임을 깔아서 할 것이 분명하기 때문에
  • 최근 게임들은 쉽게 질리는 것이 많고 게임 유저들이 콘텐츠 소비 속도가 매우 빠른 것이 특징
  • 이렇게 해서 클릭 수익을 얻는다면 그게 게임을 계속하게해서 아이템을 판매해서 얻는 것보다 수익이 더 낫기 때문
  • 어차피 모든 사용자는 언젠가는 게임을 그만할 것이기 때문에 고객 리텐션을 크게 생각하지 않고 광고를 하게 만드는 전략

※ 현재 설치된 앱은 모바일 사용자의 특성을 나타낸다.

  • 게임 앱을 설치해서 게임을 많이 하는 사람은 게임을 또 설치할 가능성이 높다. 따라서 게임 앱에 다른 게임 광고를 하는 것은 매우 효과적이다.
  • 이커머스의 버티컬 상품도 마찬가지다. 고기를 판매하고 싶으면 육류 앱이나 신선식품 앱에 광고를 하는 것이 효율이 가장 좋다. 그들은 이미 육류나 신선식품에 대해 매우 관심이 많고 적극적이기 때문이다.

같은 카테고리의 앱에서 같은 카테고리의 상품 광고를 하는 것은 매우 효과적이 수 있다

나이키 의류 앱이 있다면 현실적으로는 어려울 수 있겠지만 여기에서 아디다스나 다른 스포츠웨어 광고를 한다면 매우 클릭율이 높을 수 있습니다.

이런 것을 이용해서 많은 버티컬 이커머스(특정 카테고리만 판매하는 쇼핑몰)나 종합 이커머스에서는 메타 쇼핑이라는 것을 하려고 비즈니스 전환을 많이 하고 있습니다.

즉 메타쇼핑같은 곳에서 어떤 카테고리 또는 여러 카테고리의 상품을 모아서 추천시스템 같은 것을 해서 잘 보여주고 광고를 한다면 일반 광고 매체보다 클릭율과 구매율이 더 높아질 가능성이 매우 큰 것입니다.

이것은 이미 메타쇼핑 또는 버티컬 쇼핑에 자주 접속하는 사용자라면 적극적으로 제품을 구매할 의향이 있다는 것이며 구매에 적극적이기 때문에 정보를 얻기 위해서 클릭에도 적극적입니다.

카니발라이제이션은 어떻게 피하나?

예를 들면 특정 육류 판매 쇼핑 앱에서 타사의 육류 상품을 판매한다면 자사의 육류가 판매되지 않을 것이기 때문에 문제가 됩니다.

이 문제를 해결하는 방법은 매우 간단합니다.
회사를 여러 개 설립해서 만든 후에 브랜드와 상표를 다르게 하고 동일한 육류를 판매하는 것입니다.

일종의 트릭이지만 잘 알려진 예로 음식배달이 있습니다.

음식배달에도 많이 사용하는 방법으로 같은 업소가 여러 음식을 다른 상호로 배달앱에 등록하는 경우입니다. 이렇게 하면 음식업체에서는 전화를 받을 화률이 매우 높아 집니다. 물론 배달앱의 검색에서 상위에 나오게 하기 위해서 광고비, 홍보비가 많이 드는 것은 별개의 문제입니다.


CDP (Customer Data Platform) 고객 데이터 플랫폼은 무엇인가?

CDP의 정의

CDP는 디지털마케팅과 관련된 고객 데이터 관리 및 분석 플랫폼입니다.

여기서 말하는 고객 데이터는 주로 고객의 행적 데이터입니다.

언제 쇼핑몰에 접근하고 어떤 물건을 조회하고 샀는지와 같은 것들입니다.

자세히 말하는 CPD는 온라인쇼핑몰 같은 이커머스 비즈니스 또는 온라인 / 오프라인 비즈니스가 가능한 곳에서 자사의 몰 또는 비즈니스 플랫폼에 접속, 접근하는 고객들의 행적 데이터를 수집, 통합, 분석해서 마케팅에 활용하게 해주는 플랫폼입니다.

CDP는 유료 플랫폼을 사용하거나 자사가 직접 구축해서 사용하는데 클라우드 중에서는 Google CDP와 그 외에 몇개의 솔루션이 있습니다.

구글어낼리틱스 Google Analytics(줄여서 GA라고 부름)도 CDP의 일종이지만 CDP는 GA보다 더 세분화되고 깊은 수준의 인사이트를 얻을 수 있도록 합니다. 그리고 구글은 GA가 아닌 별도의 CDP 솔루션을 제안하고 있습니다.

https://cloud.google.com/solutions/customer-data-platform#section-2

CDP와 DMP의 차이

애드테크(광고IT)에서는 DMP (Data Management Platform)이라는 것이 있는데 CDP와 유사한 개념이라서 혼동이 생길 것입니다.

다음과 같은 차이가 있습니다.

  • CDP는 자사의 데이터를 온, 오프라인 플랫폼에서 가져와 통합하기 때문에 고객의 개인식별정보를 가지고 있고 고객의 개인정보도 적극 활용합니다.
    그에 반해
  • DMP는 제3자가 자사의 데이터를 관리하고 타사의 데이터와 연동하거나 하게 해주기 때문에 공식적으로 비식별 데이터만을 다룹니다.

CDP와 데이터과학의 관계

매우 밀접한 관계가 있습니다. CDP는 고객의 행적 데이터를 수집하고 분석합니다.

이런 데이터는 기계학습을 이용한 고객 세그멘테이션, 고객 상품 추천, RFM 분석과 코호트 분석을 통한 고객 리텐션에 활용할 수 있습니다.

특히 가장 유용하게 사용할 수 있는 것이 고객 이탈방지를 위한 CLV(Customer Lifetime Value)와 상품 추천입니다.

쉽게 생각하면 넷플릭스를 생각하면 됩니다.

넷플릭스는 고객들이 어떤 콘텐츠를 봤는지 패턴을 파악해서 고객들에 좋아할만하고 지식재산권 비용이 낮은 비교적 오래된 콘텐츠를 추천해서 고객들이 이탈하지 않게 만들어서 구독료로 이윤을 남깁니다.

은전한닢 MeCab Python 설치하기

메카브(MeCab)는 일본어 형태소분석기입니다.

은전한닢은 메카브를 한국어용으로 포팅한 것이고 Mecab-Ko 라고도 부릅니다.

은전한닢으로 텍스트마이닝, 자연어처리를 하거나 은전한닢에 의존성이 있는 소스코드, 패키지를 쓰려고 하면 메카브를 설치해야 하는데 이게 설치가 깔끔하게 잘 안되는 편입니다.

Mecab-ko의 코어 모듈과 Python 모듈까지 설치하는 방법입니다.

간단하게 한 셀로 정리했으니 순서대로 하면 됩니다.

# 아래의 명령으로 설치가 되야 하는데 안되며 포기
# sudo python3.9 -m pip install -v python-mecab-ko

# 메카브의 소스를 받와서 빌드후 설치
wget https://bitbucket.org/eunjeon/mecab-ko/downloads/mecab-0.996-ko-0.9.2.tar.gz
tar xzvf mecab-0.996-ko-0.9.2.tar.gz
cd mecab-0.996-ko-0.9.2
./configure
make
sudo make install

# 메카브 한국어 사전을 받아와서 빌드 후 설치
cd
wget https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-2.1.1-20180720.tar.gz
tar xvfz mecab-ko-dic-2.1.1-20180720.tar.gz
cd mecab-ko-dic-2.1.1-20180720
./configure
sudo apt-get install autoconf
# autogen.sh
# autoreconf
# /etc/ld.so.conf파일에 마지막 한 줄을 추가하고 다시 수행하면 정상적으로 표시가 됩니다.
sudo vim /etc/ld.so.conf
# 아래의 두줄이 들어가면 오케이
# include ld.so.conf.d/*.conf
# /usr/local/lib
sudo ldconfig
make
sudo make install
# 이제 메카브 파이썬 모듀을 설치한다
cd
git clone https://bitbucket.org/eunjeon/mecab-python-0.996.git
cd mecab-python-0.996
python3 setup.py build
python3 setup.py install
# python3 실행해서 다음 코드를 실행해서 에러가 없으면 오케이
# import MeCab

시간대에 따른 온라인 고객의 구매패턴 분석

시계열로 고객의 구매패턴을 확인하려면 많은 드릴다운과 데이터 탐색이 필요합니다. 하지만 간단한 특징으로 몇 가지 중요한 인사이트를 얻을 수도 있습니다.

가장 짧은 계졀단위를 먼저 본다

사람의 계절성(Seasonality) 중 가장 짧은 것은 하루입니다. 하루 다위로 어떻게 행동이 반복되는지 보면됩니다.

데이터 탐색에 의한 인사이트

그래프와 자료를 공유할 수는 없지만 위의 데이터는 다음과 같은 간단한 인사이트가 있습니다.

  • 가장 인터넷서핑이 활발한 시간은 10시 ~ 11시, 13시 ~ 18시, 20시 ~ 23시입니다.
  • 구매는 보통 오전 9시경 ~ 10시경, 오후 7시에 새벽 13시까지에 가장 많이 발생한다.

1일 일과의 사용자들의 웹서핑 패턴과 구매 패턴을 분석하면 광고클릭모델이나 광고전환모델을 만들 때 매우 유용한 특성, 자질(feature)에 대한 힌트를 얻을 수도 있습니다.

데이터 설명

우선 위의 그림은 2022년 9월의 추석연휴를 전후로 7일간의 인터넷 사용자들의 여러 웹사이트에서 발생한 웹사이트의 페이지뷰 중의 일부 트래픽의 패턴입니다. PC와 Mobile을 모두 포함한 것인데 모바일과 PC는 양상이 조금 다르긴 합니다.

웹사이트 페이지뷰와 사용자 구매패턴과의 상관관계

여기서 말하는 웹사이트는 뉴스, 신문, 커뮤니티, 각종 블로그를 말하고 인터넷 사용자는 매체를 돌아다니며 콘텐츠를 섭취하는 사람들을 말합니다. 이 사람들은 이런 매체들을 돌아다니가 어느 시점에 광고를 클릭하거나 또는 직접 쇼핑몰에 직접접속해서 물건을 보고 구매를 합니다.

웹사이트 페이지뷰와 사용자들의 구매 패턴과는 상관관계가 있을까? 하는 궁금증이 생길 것입니다.

단순한 아이디어로는 “어느 시간대에 광고를 보여주면 물건을 살까?” 같은 것이 있습니다.

인터넷서핑이 활발한 시간은 직장인들의 출퇴근 시간과 직장내에서의 행동패턴과 관련이 있습니다. 출근 후 앉아서 시간을 때우고 싶어지는 시간대입니다.

구매는 이것과는 다른데 구매는 정신이 또렷하고 바쁘지 않으면서 올바른 판단을 할 수 있는 시간대입니다. 이 시간대에는 구매하려고 봐 두었던 물건의 구매를 확정하거나 가격대 또는 유형이 비슷한 물건을 찾아다니는 특성이 있습니다.

그외에 소소한 인사이트로는

  • PC사용자에 비해 모바일 사용자는 새벽시간대의 트래픽이 조금 더 많다.

위의 이유로 추정할 수 있는 것은

PC나 데스크탑은 누워서 쓰거나 할 수 없지만 모바일은 편안하게 누워서 새벽까지 사용가능하기 때문입니다. 이 시간대에 사용자들이 소비하는 컨텐츠는 게임, 웹툰, 소설, 틱톡, 유튜브 같은 엔터테인먼트가 많습니다.

Ubuntu microk8s와 fluentd 설치하기

fluentd는 데이터 인제스쳔(Data ingestion) 레이어를 구성하는데 매우 유용한 도구입니다.

fluentd를 microk8s로 구성하는 방법입니다.

우분투(Ubuntu)에 microk8s 설치하기

microk8s는 snap으로 설치해야 합니다.

그래서 snap이 없는 우분투 구버전은 먼저 snap부터 설치합니다. 최근 우분투에는 snap이 기본 설치되어 있습니다.

snap설치

sudo apt-get install snapd

microk8s 설치

sudo snap install microk8s –classic

helm3 활성화

계정을 root로 전환합니다. 일반 사용자로 해도 되지만 몇 가지 선행작업이 있어서 조금 귀찮습니다. 여기서는 그냥 root로 하겠습니다.

sudo su –
microk8s enable helm3
microk8s helm3 init

init을 하면 이런 에러가 발생할수도 있습니다.

Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com
Error: error initializing: Looks like “https://kubernetes-charts.storage.googleapis.com” is not a valid chart repository or cannot be reached: Failed to fetch https://kubernetes-charts.storage.googleapis.com/index.yaml : 403 Forbidden

이럴 때는 다음과 같이 해결합니다.

해결법

Use the –stable-repo-url argument to specify the new repository:

helm init –stable-repo-url https://charts.helm.sh/stable –service-account tiller
Use the –skip-refresh argument and replace the stable repo:

해결법 실행명령

helm init –client-only –skip-refresh
helm repo rm stable
helm repo add stable https://charts.helm.sh/stable
Upgrade helm to 2.17.0 or later.

이제 fluentd의 helm 레파지토리를 추가합니다.

fluentd helm 레파지토리 추가

microk8s helm3 repo add fluent https://fluent.github.io/helm-charts
microk8s helm3 repo update

fluentd 설치

fluentd를 설치합니다.

microk8s helm3 install fluentd fluent/fluentd

fleuntd의 기본 values를 봅니다.

microk8s helm3 show values fluent/fluentd

fluend가 실행되어 있는지 서비스 확인

root@pr-01:~# microk8s kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
Kubernetes ClusterIP 10.152.183.1 443/TCP 3h16m
fluentd ClusterIP 10.152.183.249 24231/TCP 26m

A/B 테스트를 하고도 잘못된 결정을 하는 이유

A/B 테스트를 한다고 하지만 정작 테스트 결과를 왜곡해서 해석하거나 자기가 해석하고 싶은대로 해석하는 경우가 많습니다. 오늘은 온라인 서비스에서 하는 A/B테스트에 대한 불편한 사실에 대해서 얘기해 보겠습니다.

A/B테스트의 개념을 제대로 알자

A/B 테스트는 통계학의 실험계획법의 하나입니다. 역사가 오래된 과학적 실험 및 결과 확인 방법입니다. A/B테스트는 의료과학에서 정말 많이하는데 신약, 수술법, 처치법에 대한 테스트를 하기위해서 하고 온라인 서비스에서 UI의 변경이나 기능변경을 할 때 어떤 것이 좋은지 확인할 때도 씁니다.

실험대상을 A군과 B군으로 나누고 B군에 벼환를 주고 그 결과의 차이를 비교한다는 의미해서 A/B 테스트라고 부릅니다.

간단하게 정리하면

아무 처치도 하지 않은 콘트롤 그룹(Control Group, A)과
어떤 처치를 한 테스트 그룹(Threatment Group B)을 두고

  • Control Group 콘트롤그룹: 아무 처치도 하지 않은 것
  • Treatment Group 트리트먼트 테스트 그룹: 어떤 특정한 처치를 한 것

이때 Threatment group은 여러개가 있을 수 있습니다. T1, T2, T3이렇게 번호를 붙여서 여러가지 다른 처치를 하게 할 수도 있습니다. 온라인 서비스의 UI라면 UI1, UI2, UI3과 같이 새 UI를 한 번에 테스트해볼 수 있습니다.

콘트롤 그룹과 테스트 그룹의 샘플 수는 같아야 한다

콘트롤 그룹과 트리트먼트 그룹의 샘플 수는 같아야 합니다.
만약 사용자를 대상으로 하는 UI 버킷테스트라면 적용 받는 사용자는 동일하게 분할해야 합니다.

정확히 샘플 수가 같을 필요는 없고 카이스퀘어 테스트를 해서 균둥하다고 나올 정도면 됩니다.

최소한 시즌이 두 번은 반복될 수 있는 기간 동안 진행한다

여기서 말하는시즌은 온라인 서비스의 경우에는 2주를 말합니다. 월별로 특성을 타는 테스트라면 2개월은 돌려야합니다. 시즌을 2번 돌리게 하는 것은 시즌내에서는 특정 시점에 따라 기복이 있을 수 있고 잠시 튀는 경우가 생기기 때문입니다. 그리고 행위나 반응에 대한 샘플 수를 늘리기 위한 것입니다.

여기서 “하루 또는 1시간만하고 테스트 결과가 좋으니 테스트가 더 좋다”라고 판단하는 분들이 많은데 이게 좀 문제입니다. 과학적으로 보면 이건 사기나 마찬가지입니다.

어째서 1시간만 해도 되는지 1일만 해도 되는지 그게 괜찮은지에 대한 근거가 전혀 없습니다. 보통 왜 그 기간동안 하느냐라고 물으면 “그 정도면 충분하지 않을까요?” 라고 말합니다.

매우 비과학적인 사고여서 통계학에서 절대 하지 말아야 할 행위로 규정하고 있는 것입니다.
저렇게 하는 이유는 어떤 테스트 방법으로 어떻게 평가해야 하는지 모르기 때문입니다.

어떤 평가 방법을 써야 하는가?

A/B테스트는 실험을 시작하고 시간이 경과한 후 또는 어떤 처치를 한 후에 두 그룹의 차이가 있는지 없는지, 어떤 것이 더 좋은지를 확인하는 것입니다.

검정법

진행 후에 결과에 대한 검증법은 통계적 검정법을 쓰는데 통계적 검정법은 간단하게는 t-test부터 F-test 등 매우 많습니다. 샘플 수, 상황, 데이터의 분포에 따라 어떤 평가방법을 써야 하는지 각각 다르므로 어떤 평가방법을 써야하는지는 잘 알고 있어야 합니다.

T-test면 다되나?

평균의 유의미한 차이는 T-test를 하면 되고 원래 두 그룹의 평균차이가 달랐다면 부산분석을 통해 분산이 차이가 발생했는지 유의미한지를 확인해야합니다.

CTR이 좋아졌는지 보려면?

예를들어 테스트그룹1이 콘트롤그룹보다 CTR이 좋은지 보려면 2주간 버킷테스를 진행하고 CTR에 대한 T-test를 수행하면됩니다. 이때 CTR의 분포가 정규분포에 가까워야 합니다.

CTR은 하루 또는 전체 기간의 CTR을 계산하는 것이 통상적인데 페이지뷰는 있지만 CTR이 없는 경우에는 CTR이 계산이 안되는 것들은 버리고 불균등한 샘플의 숫자는 많은쪽에서 일부 줄여서 버려야 합니다.

의료과학에서의 A/B테스트

의료과학에서는 실험 대상의 샘플도 적고 콘트롤이 잘 안되고 관찰도 잘 안되는 문제 때문에 매우 어렵습니다. 온라인의 경우에는 콘트롤이 잘되고 샘플도 많습니다만 정작 실험 후에는 판단을 엉망으로 해서 잘못된 판단을 하는 것이 문제지만 의료과학은 케이스가 그때그때 다들 다르다는 문제가 있습니다. 그래서 그때 그때 방법을 선택해서 검정을 해야 합니다. 케이스별로 잘 알려진 통계적 검정법이 있는데 어떤 것을 써야 할지 애매할 때가 많습니다. 이런 경우에는 의료통계 전문가에게 물어봐야 합니다.

의료과학은 결과에 대한 검증이 매우 예민하고 철저하기 때문에 잘 해야하는데 사용해야 합니다. R언어를 사용하는 분들은 논문이 이미 R언어를 사용해서 실험을 평가한 것이 많으므로 관련 논문을 참조하거나 커뮤니티에 물어보면 어떤 테스트를 써야하는지 잘 알려주니 적극 활용할 필요가 있습니다. 미국의 유명한 의료과학 대학과 제약회사들은 모두 R언어를 기본으로 사용합니다.

그래서…

A/B테스트는 버킷을 분리해서 서로 다른 효과를 적용하게 만드는 시스템을 만드는 것이 가장 어렵습니다.

하지만 버킷테스트를 진행하고 나서 실험결과에 대한 올바른 과학적 해석과 그 논리적 결함, 통계적 해석 왜곡에 대한 검증도 매우 중요합니다.

테스트를 진행하고 단편적인 결과만 보거나 자신에게 유리한 것만 본다면 실패한 실험이 되므로 매우 주의해야 합니다.

의료과학에서 얼마나 철저하게 검증하는지 안다면 A/B테스트가 만만하지 않다는 것을 알 수 있습니다. 물론 온라인 서비스의 버킷테스트는 의료과학과는 달리 사람의 생명에 직접적연 영향을 주지 않을

만약 실험 결과에 대한 해석과 검정을 어떻게 하는지 모른다면 아예 하지 않는 것이 오히려 좋습니다.

A/B테스트를 진행하고 나서 그 결과가 믿을 만한 것인지 알고 싶다면 통계학의 가설검정법에 대해 공부해야 합니다.

한국 회사들이 데이터 기반 의사결정에 실패하는 이유

데이터 기반으로 의사결정을 하는 것은 이미 전세계적으로 당연히 해야 할 것으로 다를 인지하고 있습니다.

하지만 많은 한국회사들은 빅데이터, 데이터과학, 디지털트랜스포메이션을 도입해서 데이터기반 의사결정을 하려고하지만 대부분 실패를 맛보고 예전에 하던 경험기반의 주먹구구식 의사결정을 합니다.

데이터 기반 의사결정이 실패하는 대부분의 이유는 데이터 과학이 사기이거나 데이터 과학자의 역량 부족이나 실패보다는 경영자나 관리자 또는 조직원들의 문제인 경우가 대부분입니다.

즉 실행을 하는 사람들의 인식과 사고와 이해 관계의 문제입니다.

사람의 문제가 대부분입니다.

많은 한국회사들이 지난 십 수년동안 데이터 기반 의사결정을 하기 위한 시도를 했지만 제대로 한 곳은 거의 없습니다. 많은 회사들의 데이터 책임자, 실무자, 의사결정권자들과 얘기하거나 하다보면 처음에는 데이터 기반 의사결정이 꼭 필요하며 꼭 하고 싶다는 말과 함께 시작하지만 대부분 실패하게 됩니다.

여기에는 회사들 마다 나름대로 원인과 이유가 있겠지만 공통적으로 보이는 어이없는 원인들도 있습니다.

우선 조직내에서 수직적 레벨로 어느 위치에 있는지에 따른 문제점들입니다.

결정권자들의 문제 (탑 레벨의 문제)

결정권자들의 경우입니다. 이 경우가 문제가 가장 많습니다. 전후가 어쨌든 의사결정을 하는 최종 결정권자들이기 때문입니다.

보통 조직(회사)내에서는 결정권자들이 데이터기반 의사결정에 대해 무지하거나 잘못된 결정을 하는 것에 대해서 아무도 지적하거나 언급하지 않습니다. 이런 걸 잘못해서 결정권자의 귀에 그런 의견을 말한 사실이 알려지면 속된말로 찍혀서 인사상 불이익을 받거나 하는 문제에 휘말릴 수 있기 때문입니다. 사회생활 잘하고 싶은 것입니다.

필자가 듣거나 경험해 본 결정권자들의 문제는 여러가지 케이스로 나타납니다.

데이터기반 의사걸정을 하는 모양새만 갖추고 싶어한다

원래부터 데이터 기반 의사결정은 할 생각이 없거나 그게 뭔지 본질은 관심이 없는 케이스입니다. 본인이 데이터 기반 의사결정을 하는 합리적이고 선진화된 사람으로 각색되어 보여주길 원하는 것이고 실상 결정을 할 때는 자기가 하고싶은대로 해버립니다.

“데이터로 파악한다고 다 아는 것도 아니고 다 맞는 것도 아니잖아?” 이렇게 생각하거나 말하는 경우도 매우 많습니다.

데이터기반 의사결정 필요성을 아예 모르는 경우도 많습니다. 그냥 남들이 그걸 한다고 하고 그걸 하면 괜찮은 의사결정권자로 보일 것 같으니 그게 포장용으로 필요할 뿐입니다.

“나는 데이터기반 의사결정을 할 줄 아는 선진적이고 진보된 사람이야.” 라는 말을 하며 그런 사람으로 알려지길 바라지만 실제로 행동은 그렇게 하지 않는 것입니다.

수단과 목적이 바뀐 것입니다. 의사결정을 잘하기 위한 것이 목적이고 데이터기반 의사결정은 그걸 하기 위한 방법 중 하나입니다. 그런데 데이터 기반 의사결정을 한다는 것만 보여주고 싶은 것이 목적이고 그 수단으로 그걸 한다는 포장만 하는 것입니다.

안타깝게도 어떤 기업이든지 이런 사람이 거의 필연적으로 그리도 다수 존재합니다.

보고 싶은 것만 본다

데이터 기반의 분석결과는 그 분석이 틀리지 않고 맞다는 전제하라면 좋은 결과가 나올 수도 있고 안좋은 결과가 있을 수도 있고 세부적으로는 좋고 나쁨이 섞여 있을 수 있습니다.

이 중에서 자기가 보고 싶은 것만 봅니다. 그러니까 자기가 하고 싶은 것을지지하는 결과만을 선택하고 그게 아닌 결과는 무시해 버립니다.

이렇게 할꺼면 데이터를 확인할 필요가 없습니다. 그냥 자기가 하고 싶은 대로 하면 됩니다. 하지만 그렇게하면 비론리적이라는 말을 듣기 때문에 논리적이라는 말을 듣기 위한 포장용으로 자신에게 유리한 결가만 필요한 것입니다.

어떤 실험, 사실 탐색, 인사이트 도출과 같은 것은 보통 좋은 사실과 나쁜 사실이 뒤섞여 나오는경우가 많습니다. 대표적인 실수는 여기에서 자신이 원하는 결과에 유리한 것만 채택하고 나머지는 별거 아니라고 무시해 버리는 것은 가장 경계해야 할 것이고 그렇게 하지 않는 것은 도덕적으로 문제가 있는 것입니다.

데이터를 보긴 하지만 결정 자체를 안한다

의사결정이란 시의적절하게 해야 합니다. 즉 할 때는 해야 하는데 무조건 의사결정을 안합니다. 데이터를 보는 이유는 사람의 경험에 의한 의사결정이 왜곡이 많거나 틀릴 위험이 많기 때문에 최대한 현실을 제대로 보고 참고해서 결정을 하기 위한 것입니다.

결정을 안 하는 결정권자는 데이터 기반이든 아니든 문제가 매우 많습니다.

이런 결정권자가 있는 회사는 서서히 망합니다.

다행인 것은 당장 망하지는 않습니다. 하지만 더 불행인 것은 이런 회사는 반드시 망합니다.

매니지먼트 레벨들의 문제

본부장, 센터장, 사업장, 유닛장, 팀장 등과 같은 상위 또는 중간 매니저들의 문제입니다.

이런 사람들도 데이터기반 의사결정에 문제를 만드는 경우가 많습니다. 사실 문제를 가장 많이 만드는 사람들은 이 사람들입니다.

위에서 하라고 시키니까 하는 척만 한다

위에서 “데이터 기반으로 의사결정” 하자고 탑다운으로 지시가 내려온 경우입니다. 그게 뭔지도 모르겠고 인터넷 검색을 하고 업체를 찾아서 하는 시늉을 합니다.

그러고나서 “이거 잘 안되는거네. 거봐 사기라니깐” 이렇게 말합니다.

원래부터 하고 싶은 생각이 없었던 것입니다.

뭔지, 왜 해야하는지 학습할 생각은 없습니다. 뭔지 다 이해했지만 본인이 충분히 잘하기 때문에 그런 it인력이나 솔루션 업체들 돈이나 퍼주는 그런 것은 낭비라고 생각하는 것입니다.

부하직원에게 말해도 무슨 말인지 알아듣지 못한다

데이터 기반을 왜 해야하는지 같이 일을 해야 할 팀 동룝 또는 부하직원들이 이해를 못하는 경우입니다. 혼자 데이터 추출하고 데이터 검증을 하거나 데이터 관련 부서로부터 협조를 받아야 하지만 그렇게 하지 못하는 경우도 많습니다.

데이터 기반 의사결정에 필요한 기술이 없다

태블로 같은 BI도구를 사거나 하둡, 스파크, 빅쿼리, GCP같은 것을 써서 카운트를 세고 그래프를 예쁘게 그리고 나서 의사결정을 하면 데이터기반 의사결정이라고 생각해버립니다.

데이터를 집계하고 시각화하는 것이 데이터 기반 의사결정을 하기 위한 출발점이긴하지만 데이터 기반 의사결정은 그런 그래프와 데이터를 보고 여러가지 고민과 생각과 탐색을 해서 결론을 내는 것입니다. 즉 데이터를 제대로 집계하거나 추출, 가공하고 시각화한 데이터 요약을 해석 하는 방법을 터득해야 합니다. 그런데 그 방법은 익히기 매우 어려운 기술이고 잘 정리된 튜토리얼이 없습니다.

그래서 본인이 잘하고 있다고 착각하기 쉽지만 실상은 아닌 경우가 많습니다.

실무자들의 문제

마지막으로 실무자들의 문제가 있습니다. 즉 데이터 과학자, 데이터 분석가가 아닌 사람들입니다.

대부분의 실무자들은 데이터기반의 어쩌고 하는 것에 대해 기본적인 거부감을 가지고 있습니다.

뭔지 잘 모를말로 자신들보다 지적, 과학적으로 우위에 있다는 것을 과대포장하기 위해 데이터기반이라는 것을 만들어냈다고 생각하는 것입니다.

“실제로 해보니 안되드라”

데이터분석을 하고 인사이트 도출을 위한 미팅을 하기 위해서 초기 셋업 미팅을 하면 이런 피드백을 꽤 많이 합니다.

그리고 이런 상황에서 시작하는 프로젝트는 실상을 보면 애초에 협조하거나 잘되길 바라지 않고 방해하는 일이 허다합니다.

데이터기반으로 의사결정을 하게 되면 경험기반의 자신들의 노하우가 쓸모가 없어지는 것 같고 컴퓨터에게 자신들의 일자리를 잃어버릴 것 같은 느낌 때문입니다.

즉 애초레 제대로 할 생각도 없었고 잘 안되길 바라고 그렇게 되도록 행동한 것입니다.

“내가 진짜로 여러 번 같이 해봤는데 그거 현실성이 없더라니깐”

이렇게 말하는 사람들도 다수입니다.

앞서 말했듯이 제대로 안해봤거나 사실은 여러번 안해본 것입니다.

반약 데이터기반 의사결정이라는 것이 말만 그럴듯하고 정말로 안되는 거라면 데이터기반 의사결정은 꼭 필요한 것이며 많은 실수를 바로잡았다고 말해온 실리콘벨리의 선진적인 회사들은 모두 단체로 거짓말과 사기를 치고 있는 것입니다.

R에서 Hashmap 사용하기

대부분의 컴퓨터언어에는 키로 값을 꺼내올 수 있는 자료구조인 hashmap을 제공합니다.

Python에는 자료구조 딕셔너리 dictionary를 지원합니다.

R에도 env라는 것이 있어서 딕셔너리 형태로 쓸 수는 있지만 R의 environment는 작업 공간으로도 사용되기 때문에 사용하기 복잡하고 부담스럽습니다. 학습장벽도 높은 편입니다.

그런데 다행히도 r2r 패키지라는 것이 있어서 이 패키지를 이용하면 R에서도 hashmap을 쓸 수 있습니다.

R-Object to R-Object Hash Maps

해시 테이블은 효율적인 코딩을 위한 가장 유용한 자료구조 중 하나입니다. 추상적으로 해시 테이블은 고유 키(문자열, 숫자 또는 더 복잡한 객체일 수 있음)로 값을 가르키게 한다고 생각 할 수 있습니다. 계산적 관점에서 볼 때 가장 두드러진 특징은 읽기/쓰기 작업(예: 특정 키 또는 키-값 쌍 저장, 검색 또는 삭제)이 테이블과 관계없이 평균 시간복잡도가 O(1)입니다.

많은 프로그래밍 언어는 해시 테이블이 각각의 방법으로 구현된 것이 제공됩니다. 예를 들면 C++의 std::unordered_map/sets와 Python의 dicts 및 set이 있습니다. 기본 R에서는 해시 테이블에 가장 가까운 객체는 environment입니다. 하지만 environment는사용자의 관점에서 처리하기 다소 번거로울 수 있으며 문자열타입의 키만 지원합니다.

r2r패키지는 기본 R 환경에서 제공하는 environment보다 R에서 쓸 수 있는 더 유연한 해시 테이블 기능을 구현해서 제공합니다.

특히 r2r 해시 테이블은 다음을 지원합니다.

  • 키와 값으로 임의의 R 객체
  • 임의의 키 비교 및 해시 함수
  • 누락된 키 예외에 대한 사용자 정의 가능한 동작(기본값 던지거나 반환)

여기에서는 r2r 해시 테이블에 대한 간단한 실습용 코드를 소개합니다.

우선 r2r 패키지를 로딩합니다.

library(r2r)

기본 사용법 Basic Manipulations

다음을 사용하여 빈 해시맵(해시 테이블)을 만듭니다.

m <- hashmap()

여러 가지 방법으로 m이라는 해시맵에 키-값 쌍을 삽입할 수 있습니다.

m[["key"]] <- "value" 
m[c(1, 2, 3)] <- c("a", "b", "c") 
# Vectorized over keys and values 
m[[c(4, 5, 6)]] <- c("d", "e", "f") 
# Not vectorized

다음 쿼리는 위의 설명에서 언급한 [[ 및 [ 연산자 간의 차이점을 설명합니다.

m[["key"]]
#> [1] "value"

m[c(1, 2, 3)]
#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "b"
#> 
#> [[3]]
#> [1] "c"
m[[c(1, 2, 3)]]
#> NULL

m[c(4, 5, 6)]
#> [[1]]
#> NULL
#> 
#> [[2]]
#> NULL
#> 
#> [[3]]
#> NULL
m[[c(4, 5, 6)]]
#> [1] "d" "e" "f"

단일 요소 삽입 및 쿼리는 제네릭 insert() 및 query()를 통해 수행할 수도 있습니다.

insert(m, "user", "vgherard") # Modifies `m` in place
query(m, "user")
#> [1] "vgherard"

세트 Sets

해시 테이블 외에도 단순히 키를 저장하는 해시 세트를 만들 수도 있습니다.

s <- hashset()
insert(s, 1)
s[[2]] <- T # equivalent to insert(s, 2)
s[c(1, 2, 3)]
#> [[1]]
#> [1] TRUE
#> 
#> [[2]]
#> [1] TRUE
#> 
#> [[3]]
#> [1] FALSE

키와 값의 타입 Key and value types

키와 값으로 사용할 수 있는 개체 유형에는 제한이 없습니다.

예를 들면 다음과 같이 모델을 키로 사용할 수도 있습니다.

m[[ lm(wt ~ mpg, mtcars) ]] <- list("This is my fit!", 840)
m[[ lm(wt ~ mpg, mtcars) ]]
#> [[1]]
#> [1] "This is my fit!"
#> 
#> [[2]]
#> [1] 840
m[[ lm(cyl ~ mpg, mtcars) ]]
#> NULL

기본값 설정하기 Setting default values

누락된 키에 대한 기본값을 설정할 수 있습니다.

다음은 그 예입니다.

m <- hashmap(default = 0)

이 기능은 카운터를 만드는 데 유용합니다.

objects <- list(1, 1, "1", FALSE, "1", 1)
for (object in objects)
    m[[object]] <- m[[object]] + 1
m[["1"]]
#> [1] 2

누락된 키를 참조하려고 할 때 exception을 throw할 수 있습니다.

m <- hashmap(on_missing_key = "throw")
tryCatch(m[["Missing key"]], error = function(cnd) "Oops!")
#> [1] "Oops!"

커스텀 키 비교와 해시 함수 Using custom key comparison and hash functions

hashmaps와 hashmaps는 기본적으로 base::identical()을 사용하여 키를 비교합니다.

m <- hashmap()
m[[1]] <- "double"
m[["1"]] <- "character"
m[[1]]
#> [1] "double"

이 동작은 키 비교 기능을 명시적으로 제공하여 변경할 수 있습니다. 올바르게 작동하게 하려면 동등한 키에 대해 동일한 해시를 생성하는 해시 함수를 명시적으로 제공해야 합니다.

이를 수행하는 간단한 방법은 다음 예제와 해시맵을 생성할 때 키에 전처리 함수를 정의할 수 있습니다.

m <- hashmap(key_preproc_fn = Arg)

키가 하나의 복소수라고 가정할 때 복소수 평면에서 방향이 같을 때 두 개의 키를 동등하게 간주합니다. 복소수 벡터의 방향은 R 함수 Arg()를 사용해서 구할 수 있기 때문에 Arg함수를 사용하는 걸이 이 경우에는 맞습니다. 생성자의 key_preproc_fn 인수를 통해 이러한 방식으로 키를 사전 처리하도록 해시맵에 지정할 수 있습니다.

의도한 대로 잘 작동하는지 확인해 봅니다.

m[list(1, 1 + 1i, 1i)] <- list("EAST", "NORTH-EAST", "NORTH")
m[[10]]
#> [1] "EAST"
m[[100i]]
#> [1] "NORTH"
m[[2 + 2i]]
#> [1] "NORTH-EAST"

참고: https://cran.r-project.org/web/packages/r2r/vignettes/r2r.html

Confusion Matrix 혼동 행렬

Confusion Matrix(컨퓨전 매트릭스)는 한국어로 혼동행렬이라고 부릅니다.

혼동행렬이라는 단어가 어색해서 흔히 영어 발음 그대로 컨퓨전 매트릭스라고 부릅니다.

Confusion matrix는 기계학습 모델 중에서 분류 모델의 성능을 측정하고 학인하기 위한 간단한 계산식과 표입니다. 기계학습의 분류모델의 성능 측정을 위한 지표 계산법 이라고 기억하시면 됩니다.

인터뷰나 멘토링을 할 때 기계학습 초보자인지 아닌지를 확인하는 가장 쉬운 방법은 Confusion Matrix를 설명하라고 하거나 어떤 모델에 대한 설명을 한 후 Confusion Matrix에서 어떤 것을 보는게 좋을지에 대해서 물어보고 대답을 어찌하는지 보면 확인할 수 있습니다.

Confusion Matrix에 대해서 잘 모른다면 기계학습에 대한 지식이 아예 없다고도 볼 수 있습니다.

흔히 Confusoin matrix는 위의 그림에서 좌상단에 있는 조그만 박스를 말하는데 기계학습을 하다가 보통 Precision, Recall과 같은 지표 이름이 나오면 Confusion matrix라고 생각하면 됩니다.

위의 표가 행렬처럼 생겨서 혼동행렬이라고 하는것인데

이름이 왜 혼동이라는 단어가 들어가서 혼동행렬인지 단어의 뜻을 이해하면 저게 왜 복잡한지 알 수 있습니다.

기계학습 모델의 문제는 “그 모델이 왜필요하며 어떤 문제를 해결하기 위해서 필요한가 ”에 따라서 어떤 지표를 봐야 하는지를 결정해야 하고 어떤 지표와 어떤 지표가 상관관계가 있는지 상호충돌(trade off)인지도 잘 이해하지 않으면 지표를 보는 것(해석하는 요령)이 어렵습니다.

그래서 혼동행렬이라고 부릅니다.

Precision을 중요하게 봐야 하는 모델, Recall을 중요하게 봐야 하는 모델, 둘 다 봐야하는 모델 등 각기 다른데 모델의 각 지표에 대한 중요도와 우선순위는 모델이 처한 상황과 산업, 모델이 해결해야 하는 문제에 따라 다릅니다.

어쨌든 혼동행렬에서 중요한 기본 4개의 지표는

  • TP: True Positive. 모델이 긍정이라고 한 것중에 정답도 긍정인 것
  • FP: False Positive. 모델은 긍정이라고 했지만 정답은 부정인 것
  • FN: False Positive. 모델이 부정이라고 한 것중에 정답이 긍정인것
  • TN: True Negative. 모델이 부정이라고 한 것중에 실제로 정답도 부정인 것

TP, TP, FN, TN은 모두 카운트한 값으로 빌드한 모델을 테스트 데이터에 대해서 실험해서 나온 결과로 구하게 됩니다.

위의 기본 지표도 상당히 헷갈리는데 간단하게 이해하려면 True와 False는 기계(모델)이 한 행위가 맞다 틀리다를 표현하는 것이고 Positive와 Netagive는 모델이 데이터 레코드를 어떻게 판별했는가를 나타냅니다.

True Positive라면 모델은 데이터레코드를 긍정이라고 판단했고 True이기 때문에 모델이 긍정이라고 한 것이 맞다! 라는 뜻입니다.

False Negative라면 모델은 데이터 레코드를 부정으로 판단했고 False이기 때문에 모델이 그렇게 판단한 것이 틀렸다는 의미입니다. 풀어서 설명하면 False Negative는 모델이 부정이라고 했지만 사실 정답은 긍정인것이라 모델이 네가티브로 판별한 것은 틀렸다는 의미입니다.

그 뒤에 2차 지표를 구하게 되는데

이것들이 precision, Recall, Accuracy, F1-score, F-beta score 같은 것들입니다.

이 지표들은 Confusion Matrix안에 있는 4개의 기초 카운트값으로 계산해서 구할 수 있고 보통 비율값으로 계산이 됩니다.

RFM 분석, RFM Analysis, 리테일 고객 분석하기

RFM에 대해서 간단하게 정리한 것을 올립니다.
더 복잡한 분석기법이나 모델링 방법은 다른 포스트에 올려보겠습니다.

RFM 정의

RFM은 마케팅 분석 방법 중 하나입니다.
온라인 리테일(물건을 판매하는 사업)에서 고객 군집을 고객의 최종 방문수, 유휴시간, 소비금액을 기준으로 나누고 각 군집이 어떻게 유지되고 변화하는지에 따라서 현재 비즈니스 상태를 파악하고 문제가 있다면 어떻게 대응해야 할지를 판단하는데 쓰는 방벘입니다.

온라인 리테일이라면 쿠팡, 위메프, 티몬, 지마켓, 11번가, SSG 등을 생각하면 쉬울 것입니다.

RFM은 디지털마케팅 기법을 이용해서 기업을 성장시키는 그로쓰해킹 (Growth Hacking)에서도 자주 쓰이는 분석지표입니다. 그래서 디지털 마케터, 비즈니스 데이터 분석가라면 반드시 알아야 하는 분석 방법입니다.

RFM의 용어 정리

RFM – Recency, Frequency, Monetary 의 각각 앞 글자를 따서 RFM이라고 부릅니다.

비슷한 것으로 RFD가 있으나 Monetary가 Duration으로 바뀐것 외에는 동일합니다. Duration는 체류기간입니다.

RFD – Recency, Frequency, Duration

RFM에서 고객의 방문 또는 구매 주기의 관점에서 볼 때 구매액은 크게 중요하지 않고 그 보다는 체류시간 같은 것이 더 중요한 비즈니스에서는 머니테리 대신 듀레이션을 사용하기도 합니다.

체류시간이 중요한 비즈니스는 게임입니다. 게임의 체류시간은 어떤 면에서는 게임에서 인앱구매를 하는 것 보다 더 중요할 수 있으며 정액제 게임이고 게임내 구매가 없는 경우라면 활성유저가 많아야 게임이 흥하기 때문입니다. 어쨌든 RFD 분석도 RFM 분석과 같은 것입니다.

RFM과 마케팅 전략

RFM을 한국어로 번역하면 최신성, 빈발성, 통화성(체류성) 으로 해석할 수 있으나 한국어로 번역하면 매우 어색하므로 그대로 리센시, 프리퀀시, 머니테리로 부릅니다.

광고주가 그들의 관점에서 고객(Customer)을 세그멘테이션하고 프로파일링하고 고객의 가치를 판단하고 마케팅 전략을 세우는 데 활용하는 방법입니다.

앞서 말했듯이 리테일 비즈니스 업체 (소비재 물건을 판매하는 업체) 또는 온라인 서비스 업체(넷플릭스, 유튜브, 멜론 같은)가 고객을 분할해서 구분하고 관리하는 오래된 고객 관리 및 분석 기법입니다.

RFM 계산하기

RFM은 고객에게 R, F, M 각각의 점수를 부여하고 그 다음에 점수들을 다시 몇개의 적은 그룹으로 묶은 뒤에 구분한 그룹들을 관리하게 됩니다.

R 점수

R(Recency)은 오늘로 부터 최종 방문한 날까지의 날짜수를 계산합니다. 10일전에 왔다면 R은 10이 됩니다. R점수는 적을 수록 좋은 것입니다.

F 점수

F(Frequency)는 고객이 가입 또는 최초방문 또는 최초구매일로부터 지금까지 구매한 수입니마. 구매한 횟수 일수도 있고 구매한 물건 수 일수도 있지만 보통은 트랜잭션을 기준으로 합니다. 그러니까 결제를 한 번했다면 물건을 여러번 사도 1회로 카운트합니다. F는 높을 수록 좋습니다.

M 점수

M(Moneytary)는 구매한 금액의 총액입니다. F와 마찬가지로 지금까지 구매한 트랜잭션의 금액을 모두 더하면 됩니다. 반품이나 결제취소는 할 수 있다면 계산에서 빼야합니다.

RFM의 점수 분할 척도

R, F, M을 각각 기본 5점 척도로 분할해서 총 125가지 유형으로 고객을 중규모(세그먼트 수가 100을 넘지 않음) 분할해서 관리 계획을 세우고 대책을 만들어 정복합니다.

R, F, M은 각각 척도를 주고 양적점수에 의한 순서로 등분할 하는데 (Quantile) 척도는 3 ~ 5점 등으로 분석하는 사람과 업체에 따라 다르게 할 수 있으나 기본 5점으로 분할하는 예가 가장 많습니다.

아까 구한 R값을 기준으로 역순정렬해서 퀀타일로 고객그룹을 5개로 균등분할해서 각 고객에게 R점수를 1 ~ 5점으로 부여합니다. R은 숫자가 낮을 수록 좋은 것이기 때문에 역순정렬합니다.

F값은 순 정렬해서 역시 순서대로 5개로 균등분할해서 F점수를 부여하고 M도 마찬가지로 순정렬해서 5개로 부여합니다.

예를들어 지금까지 가입한 고객이 총 100명이라면 R=1은 20, R=2도 20, R=3도 20, R=4도 20, R=5도 20명씩이 됩니다. F와 M도 동일하게 각 점수별로 20명씩이됩니다.

퀀타일은 어떤 기준값을 가지고 정렬을 해서 순서대로 균등(또는 최대한 균등

표 – 5점 척도에 의한 RFM 분할

RecencyFrequencyMonetary
555
444
333
222
111

위와 같이 되는데 중요한 것은 나뉘는 그룹이 총 5 x 5 x 5 = 125개 일것 같지만 실제로는 125개가 안될 수도 있습니다.

R=1, F=5, M=5와 같은 특정 조합에 해당하는 고객이 한명도 없을 수 있기 때문입니다.

어쨌든 이렇게 해서 고객들은 최소 5개에서 최대 125개의 그룹으로 나눕니다. 보통 100개 이상의 그룹에 모두 고객이 존재하게 되는데 이건 관리하기 너무 많고 인사이트를 얻기에도 힘듭니다. 그래서 이 그룹들을 다시 관리하기 좋게 의미와 이름을 부여해서 나누고 관리합니다.

캠페인의 전환율을 RFM으로 파악하는 법

캠페인의 전환률이 매우 낮다면 그 이유는 적절한 고객(Customer)에게 타겟팅하지 않았기 때문입니다. 고객 세그먼트는 각각 동일한 캠페인에도 다르게 반응하기 때문입니다.

그래서 고객을 구매 행동에 따라 다르게 분류해야 할 필요가 있고 분류된 세그먼트별로 다른 접근 방법으로 다르게 접근해야 합니다.

충성고객에게는 상품이 형편없지만 않으면 구매를 합니다. 하지만 비충성 고객에게는 매리트가 충분히 있는 비교적 가격 경쟁력이 높으면서 구매 부담이 없는 제품을 캠페인으로 보여주지 않으면 클릭하지 않습니다.

RFM은 행동 기반의 고객 세그먼트를 위해 이미 증명된 마케팅 모델입니다. RFM은 거래 내역(transaction history)으로 얼마나 최근에, 얼마나 자주, 얼마나 많은 돈을 지불했는지로 고객을 그루핑(grouping) 합니다.

RFM은 파라미터 3개를 사용하는 이유는 고객 가치평가는 1개의 파라미터만으로는 부족할 수 있기 때문입니다.

RFM의 3개의 척도중에서 보통은 가장 좋은 고객은 가장 많은 금액을 지불한 고객이라는 데는 대부분 동의하지만 그 고객이 아주 오래전에 딱 한 번 구매를 했고 더 이상 우리 제품을 사용하지 않는다면 최고의 고객이 아닐 가능성이 큽니다.

그래서 RFM은 3개의 고객 속성으로 고객을 순위화(rank)합니다.

고객이 최근에 구매했다면 더 높은 점수를 주고

고객이 빈번하게 구매했다면 더 높은 점수를 주고

고객이 많은 돈을 지불했다면 더 높은 점수를 줍니다.

그리고 3가지 점수를 병합해서 RFM 점수를 만듭니다.

그런 후에 고객을 RFM(Recency – Frequency – Monetary) 점수로 서로 다른 그룹으로 분할할 수 있다. 반대로 말하면 동질 그룹으로 묶을 수 있게 됩니다.

고객을 여러 다른 세그먼트 체계로 분할 수 있지만 보통 11개 정도로 분할하는 것을 추천하고 있습니다.

RFM 세그먼트 분할표1

#세그먼트 (Customer Segment) 별칭한글 별칭활동 (Activity)대응 방안 (Actionable Tip)
1Champions챔피온Bought recently, buy often and spend the most!Reward them. Can be early adopters for new products. Will promote your brand.
2Loyal Customers로얄(충성고객)Spend good money with us often. Responsive to promotions.Upsell higher value products. Ask for reviews. Engage them.
3Potential Loyalist잠재 로얄 (잠재적 충성고객)Recent customers, but spent a good amount and bought more than once.Offer membership/loyalty program, recommend other products.
4Recent Customers단골 고객Bought most recently, but not often.Provide onboarding support, give them early success, start building a relationship.
5Promising유망 고객Recent shoppers, but haven’t spent much.Create brand awareness, offer free trials
6Customers Needing Attention주목해야 할 고객Above average recency, frequency and monetary values. May not have bought very recently though.Make limited time offers, Recommend based on past purchases. Reactivate them.
7About To Sleep휴면 직전 고객Below average recency, frequency and monetary values. Will lose them if not reactivated.Share valuable resources, recommend popular products / renewals at discount, reconnect with them.
8At Risk떠나면 위험한 고객Spent big money and purchased often. But long time ago. Need to bring them back!Send personalized emails to reconnect, offer renewals, provide helpful resources.
9Can’t Lose Them붙잡아야 할 고객Made biggest purchases, and often. But haven’t returned for a long time.Win them back via renewals or newer products, don’t lose them to competition, talk to them.
10Hibernating동면 고객Last purchase was long back, low spenders and low number of orders.Offer other relevant products and special discounts. Recreate brand value.
11Lost떠난 고객Lowest recency, frequency and monetary scores.Revive interest with reach out campaign, ignore otherwise.

RFM 세그먼트 분할표2

통계학적 RFM Analysis를 위해서 예제로 제시한 RFM 점수와 세그먼트 분할표

SEGMENTDESCRIPTIONRFM
ChampionsBought recently, buy often and spend the most4 – 54 – 54 – 5
Loyal CustomersSpend good money. Responsive to promotions2 – 43 – 44 – 5
Potential LoyalistRecent customers spent good amount, bought more than once3 – 51 – 31 – 3
New CustomersBought more recently, but not often4 – 5< 2< 2
PromisingRecent shoppers, but haven’t spent much3 – 4< 2< 2
Need AttentionAbove-average recency, frequency & monetary values3 – 43 – 43 – 4
About To SleepBelow average recency, frequency & monetary values2 – 3< 3< 3
At RiskSpent big money, purchased often but a long time ago< 32 – 52 – 5
Can’t Lose ThemMade big purchases and often, but a long time ago< 24 – 54 – 5
HibernatingLow spenders, low frequency, purchased a long time ago2 – 32 – 32 – 3
LostLowest recency, frequency & monetary scores< 2< 2< 2

이 세그먼트 분할 기준으로 여러 세그먼트에 중복 분류되는 고객군이 있을 수 있으므로 다소 문제가 있을 수 있다.

문제점

  • 조건 적용에 순서에 따라 분할되지 않은 세그먼트가 발생하므로 범위에 따른 조건의 적용 순서를 재배열 해야함
  • 조건에 포함되지 않는 고객들이 있음
    • 모든 고객들이 꼭 1개의 세그먼트에 포함되어야 하는가에 대한 결정 문제가 있음
    • 고객들이 2개 이상의 세그먼트에 겹쳐서 포함되어도 괜찮은가에 대한 결정 문제가 있음
    • 세그먼트간 경곗값이 크지 않으면 세그먼트를 합치거나 중복해야 할 수 있음

코멘트

  • RFM 그룹에 따라 광고배너의 내러티브를 변경하는 것이 더 나을 수 있음
    • 저희의 최고의 고객이십니다. 고객님이 지금 가글을 한 병 사시면 한 병 더 드립니다. 뭐 이런식으로? 해줘야 한다.

RFM 점수 계산

RFM점수는 다음의 3가지 행동 데이터를 기반으로 계산합니다.

  • Recency (R): 마지막으로 구매한 후에 오늘까지 몇일이 지났는가?
  • Frequency (F): 지금까지 전체 구매(거래)가 몇번 있었는가?
  • Monetary (M): 지금까지 전체 구매한 금액은 얼마인가?

위의 값을 계산한 후에 1 ~ 5점의 척도로 바꾸면 RFM 점수(RFM score)가 된다.

RFM 데이터 처리 흐름 Data processing workflow

비닝 binning

Percentile 또는 Quantile 기반으로 개체수에 따른 등분할 합니다. 동일하거나 거의 비슷한 수가 되도록 분할하는 것입니다.

이것은 상대적 분할이기 때문에 절대 기준이라고생각해서는 안됩니다. RFM은 상대적으로 좋은 고객인지 위험한 고객인지를 아는 것이지 절대적으로 좋은 고객 안좋은 고객을 알아내는 지표는 아닙니다.

특히 업종별로는 고객의 구매 관련 행동 패턴의 양상이 다르므로 비교하는데 사용하기 어렵지만 같은 업종끼리라면 비슷한 업종의 회사의 RFM 고객 세그먼트는 비교대상이 됩니다.

RFM의 문제점

프로파일링 문제1

세그먼트를 분할하고 분할 세그먼트에 네이밍 또는 정의(definition)을 사람에 의해서 해석해야 하는 문제. 샘플이 있으므로 샘플 이용해 시도한 후에 정의하는 방법을 알아낼 수 있습니다.

프로파일링 문제2

세그먼트 분할 후 각 세그먼트의 분포와 개체수를 확인하고 나서 문제를 알게 되는데 문제의 원인을 알기 위해서는 고객사 현업의 경험 지식이 필요합니다.

프로파일링 문제3

세그먼트에 대한 분할 예제가 있으나 주관적(업체별)일 수 있어 공통된 세그멘테이션 방법으로 진행해도 무리가 없을지에 대한 판단이 필요

  •  우선 공통 기준으로 세그먼트를 모두 나눈 뒤 업종별 또는 광고주별로 세그먼트의 분할이 어떻게 되었는지 성과는 어떠했는지, 변화는 어떻게 되어 왔는지 구분해서 비교 리포트를 작성한다.
  • 작성한 후 세그먼트 분할 기준을 각각 따로 할지 공통으로 할지 재결정한다. 가능하다면 공통 기준으로 가는 것이 비교 분석을 하기 편리하므로 그에 대한 가중치를 주고 결정을 하도록 한다.
  • 타일을 분할할 때 타일간의 대푯값의 차이가 없는 경우 타일 수를 조절해야 할 수 있는데 조절하지 않고 대푯값의 차이와 분포의 현상태만 나열해 둔다. 

RFM 세그먼트 활용 방법

간단하게는 RFM세그먼트를 약 3가지로 활용할 수 있을 것으로 기대할 수 있습니다.

현재 사업의 상태를 파악할 수 있습니다.

  • 비즈니스가 망해가고 있는지 잘되고 있는지 조치가 필요한지를 알 수 있습니다.

비즈니스 개선을 위해서 집중해야 할 세그먼트를 알아낼 수 있고 세그먼트를 공략하기 위한 캠페인 진행 방법을 선택할 수 있습니다.

  • 어떤 세그먼트에 문제가 있는지? 고객 리텐션이 필요한지, 이탈 방지가 필요한지, 신규 고객 입수가 필요한지, 기존 고객의 구매 활성화가 필요한지 등
  • 위의 해석에 따라 캠페인 상품을 깔 맞춰서 제안할 수 있고 진행을 시도할 수 있다.

역으로 특정 캠페인에 적합한 세그먼트를 찾아내서 데이터 교환으로 활용할 수 있습니다.

  • 어떤 업체의 어떤 세그먼트는 어떤 다른 업체에게는 좋은 세그먼트가 될 수 있다.
  • 통신사에서 요금제를 새로 구매한 고객 세그먼트는 핸드폰 악세사리를 판매하는 광고에 활용한다던가 (이런 것을 스토리라인 캠페인이라고 부름)

참고 자료

글을 쓰면 2D 일러스트레이션을 생성해 주는 – AI Stable Diffusion Demo


허핑페이스에 공개되었다고 합니다.

제목대로 영어로 생성할 이미지에 대한 설명을 적으면 생성을 해줍니다.

이런 종류의 AI는 이미 이전에도 많이 나와있습니다만 이 AI는 품질이 상당히 좋다는 평가입니다.

실제로도 가능하니 테스트 해보세요.

🔗접속주소: https://huggingface.co/spaces/stabilityai/stable-diffusion

Python MySQL 쿼리 결과를 dict로 가져오기 – Get dictionary from query result of MySQL

Python에서 MySQL의 DB결과를 가져올 때

cursor.fetchall()를 사용하면 MySQL결과는 보통 리스트(list) 타입으로 가져오게 되서 쿼리에서 선택한 컬럼의 번호를 주고 꺼내와야 합니다.

컬럼이 몇개 안되면 괜찮지만 컬럼이 많거나 쿼리가 복잡하면 꺼내와서 짝을 맞추는 것이 어려우니 딕셔너리 타입으로 받으며 좋습니다.
보통은 다음과 같이 하지만

rows = cursor.fetchall()
for row in rows:
  id = row[0]
  name = row[1]
  print(id, name)

딕셔너리로 사용하기는 다음과 같이 쓰는 것을 말합니다.

rows = cursor.fetchall()
for row in rows:
  id = row['id']
  name = row['name']
  print(id, name)

다음과 같이 cursor를 생성할 때 옵션을 지정하면 쓸 수 있습니다.

import pymysql
connection = pymysql.connect(db="test")
cursor = connection.cursor(pymysql.cursors.DictCursor)
cursor. Execute("SELECT ...")

위의 단점은 데이터를 가져올 때 딕셔너리에 키를 다 넣으므로 데이터의 사이즈가 커진다는 것입니다 경우에 따라서 복잡하더라도 필드의 순번으로 데이터를 꺼내오는 것이 나은 경우가 있습니다.

무분별하게 사용하지 않도록 고민은 한 번 해야합니다.

LibLinear – 멀티코어 SVM 라이브러리 multicore SVM library

sVM 전통적으로 여전히 로버스트한 분류 문제를 해결하는데 쓰는 알고리즘입니다.

하지만 SVM의 문제점은

  • 빌드된 모델이 왜 그렇게 만들어졌는지 알 수 없는 블랙박스 모형이라는 것과
  • 멀티코어로 병렬처리해서 모델을 빌드하기 어렵다

입니다.

첫번째 문제는 어쩔 수 없다고 해도 멀티코어는 이제 해결이 된 것이 있습니다.

아래 링크에 있는 liblinear입니다.

https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/multicore-liblinear/

github 주소는 이곳입니다.

https://github.com/yesimon/LIBLINEAR

간단한 기여도 계산 함수

기여도

기여도란 어떤 성과지표에서 어떤 부분집합이 전체의 성과지표에 얼마나 형향을 주었는지 계산하는 것입니다. 리프트(lift)라고도 합니다. 리프트는 알고리즘이나 계산마다 각기 다르므로 일반적으로 말하는 리프트가 이것과 동일한 것은 아닙니다.

비율값이 지표인 경우에 총 지표를 만드는데 구성된 멤버 중 하나의 기여도가 얼마인지를 알아내는 간단한 함수입니다. 비율값이 아닌 지표에서의 기요도는 그냥 전체에서 해당 멤버가 차지하는 비중을 계산하면 되기 때문에 계산할 것이 없습니다.

비율값이 KPI인 경우를 예를 하나 들면 강고 배너 캠페인 5개를 운영하고 나서 전체 CTR과 각 배너별 CTR이 있을 때 배너별로 기여도를 계산하거나 하는 경우입니다.

비율값이 KPI인 경우에 기여도 계산이 어려운 이유

위의 표와 같은 5개의 캠페인이 있는데 클릭과 노출이 다 다릅니다. 이때 캠페인1과 캠페인2는 모두 CTR 0.5로 50%씩 동일합니다. 그런데 캠페인2는 캠페인1에 비해 노출과 클릭이 각각 모두 10배 많습니다.

상식적으로 생각할 때는 이런 경우 캠페인1이 기여도가 더 높아야 하는 것입니다.
기여도 계산에서 이것이 반영되야 합니다.

코드

코드는 R로 되어 있습니다. 하려고 했던 것은 calc_contrib_origin이라는 함수에서 계산할 때 분모가 0이 되는 문제로 기여도가 아예 계산이 안되는 것을 어떻게 해결할 것인가입니다.

이때 비율을 계산하는 것이기 때문에 분모가 0이 안되도록 하는 것이 중요한데 이 부분이 생각보다 까다롭습니다.

# 원래 함수
calc_contrib_origin <- function(total_z, total_c, z, c) {
  ((total_z / total_c) - ((total_z - z) / (total_c - c)))
}
 
# 멍청한 함수 v0
calc_contrib_mod1 <- function(total_z, total_c, z, c) {
  frac <- total_c / c
  ((total_z / total_c) - ((z*frac) / (c*frac)))
}
 
# 멍청한 함수 v1
calc_contrib_mod1 <- function(total_v1, total_v2, v1, v2) {
  frac1 <- total_v1 / total_v2
  frac2 <- total_v2 / total_v1
  if ((total_v1 == v1) && (total_v2 == v2)) {
    cat("case 1\n")
    (total_v1 / total_v2)
    right <- 0
  }
  else if ((total_v1 != v1) && (total_v2 == v2)) {
    cat("case 2\n")
    (total_v1 / total_v2) - ((total_v1 - (frac2 * v1)) / v2)
    right <- ((total_v1 - (frac2 * v1)) / v2)
  }
  else if ((total_v1 == v1) && (total_v2 != v2)) {
    print("case 3\n")
    (total_v1 / total_v2) - (v1 / (total_v2 - (v2 * frac1)))
    right <- (v1 / (total_v2 - (v2 * frac1)))
  } else {  #
    cat("case 4\n")
    (total_v1 / total_v2) - ((total_v1 - v1) / (total_v2 - v2))
    right <- ((total_v1 - v1) / (total_v2 - v2))
  }
  left <- (total_v1 / total_v2)
  cat(paste0(left, " - ", right, "\n"))
  return(left - right)
}
 
# 멍청한 함수 v2
calc_contrib_mod2 <- function(total_v1, total_v2, v1, v2) {
  # frac1 <- total_v1 / v1
  # frac2 <- total_v2 / v2
  frac1 <- total_v1 / total_v2
  frac2 <- total_v2 / total_v1
  # 기준값
  if ((total_v1 == v1) && (total_v2 == v2)) {
    cat("case 1\n")
    (total_v1 / total_v2)
    right <- 0
  }
  # 분모가 0인 케이스
  else if ((total_v1 != v1) && (total_v2 == v2)) {
    cat("case 2\n")
    #total_v1 / (total_v2 - v2)
    right <- (v1 / (total_v2 - (v2 * frac1)))
  }
  # 분자가 0인 케이스
  else if ((total_v1 == v1) && (total_v2 != v2)) {
    print("case 3\n")
    right <- total_v1 / (total_v2 - v2)
  } else {  #
    cat("case 4\n")
    (total_v1 / total_v2) - ((total_v1 - v1) / (total_v2 - v2))
    right <- ((total_v1 - v1) / (total_v2 - v2))
  }
  left <- (total_v1 / total_v2)
  cat(paste0(left, " - ", right, "\n"))
  return(left - right)
}
 
# 덜 멍청한 함수 v1
calc_contrib_mod1 <- function(total_z, total_c, z, c) {
  (((total_z + 1) / (total_c + 1)) - ((total_z - z + 1) / (total_c - c + 1)))
}
 
# 덜 멍청한 함수 v2
calc_contrib_mod2 <- function(total_z, total_c, z, c) {
  lb <- 1 - 1 / (total_c + 1)
  rb <- 1 - (total_z + 1) / 1
  print(c(lb, rb, rb - lb))
  ( (((total_z + 1) / (total_c + 1)) - ((total_z - z + 1) / (total_c - c + 1))) ) / (rb - lb)
}
 
calc_contrib_mod <- calc_contrib_mod1
 
# ※ 전체 비율에서 항목값들이 존재하지 않았을 경우를 계산하는 것이 전부
# ※ 따라서 전체 비율을 계산하고 대상 항목의 수치를 포함하지 않은 것의 비율을 계산해서 뺀다
 
# 간단한 테스트
calc_contrib_mod(50, 100, 49, 60)
calc_contrib_mod(50, 100, 50, 60)
calc_contrib_mod(50, 100, 50, 59)
 
# 계산검증1. (o)
calc_contrib_mod(200, 250, 202, 250) # 아래 보다는 높아야 함 (o)
calc_contrib_mod(200, 250, 201, 250) # 아래 보다는 높아야 함 (o)
calc_contrib_mod(200, 250, 200, 250) # 기여도 100% (기준 기여도와 동일) (o)
calc_contrib_mod(200, 250, 199, 250) # 위의 것 보다는 낮아야 함 (o)
calc_contrib_mod(200, 250, 198, 250) # 위의 것 보다는 낮아야 함 (o)
 
calc_contrib_mod1(200, 250, 200, 0)
 
# 계산검증1-1 (o)
calc_contrib_mod(200, 250, 101, 50) # 아래 것 보다는 높아야 함 (o)
calc_contrib_mod(200, 250, 100, 50) # 아래 것 보다는 높아야 함 (o)
calc_contrib_mod(200, 250, 100, 51) # 위의 것 보다 낮아야 함 (o)
 
# 계산검증2 (o)
calc_contrib_mod(250, 200, 251, 200) # 기준기여도 보다 높거나 같아야 함
calc_contrib_mod(250, 200, 250, 200) # 기여도 100% (기준 기여도와 동일)
calc_contrib_mod(250, 200, 249, 200) # 위의 것 보다 낮아야 함 (o)
calc_contrib_mod(250, 200, 248, 200) # 위의 것 보다 낮아야 함 (o)
calc_contrib_mod(250, 200, 247, 200) # 위의 것 보다 낮아야 함 (o)
 
# 계산검증3 (o) 점진적으로 높아지는
calc_contrib_mod(250, 200, 50, 100)
calc_contrib_mod(250, 200, 100, 100)
calc_contrib_mod(250, 200, 100, 50)
calc_contrib_mod(250, 200, 100, 2)
calc_contrib_mod(250, 200, 100, 1)
 
# 계산검증4 (o) 점진적으로 낮아지는
calc_contrib_mod(250, 200, 100, 1)
calc_contrib_mod(250, 200, 100, 2)
calc_contrib_mod(250, 200, 100, 99)
calc_contrib_mod(250, 200, 100, 100)
calc_contrib_mod(250, 200, 100, 101)
calc_contrib_mod(250, 200, 100, 102)
 
# 계산검증5 (o). 다운 방향으로 기여도가 떨어져야함
calc_contrib_mod(110, 110, 100, 1)
calc_contrib_mod(110, 110, 100, 2)
calc_contrib_mod(110, 110, 100, 99)
calc_contrib_mod(110, 110, 100, 100)
calc_contrib_mod(110, 110, 100, 101)
calc_contrib_mod(110, 110, 100, 102)
 
# 계산검증6 (오류)
calc_contrib_mod(110, 110, 110, 1) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 2) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 99) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 100) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 101) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 102) # 아래것 보다 좋음 (o)
calc_contrib_mod(110, 110, 110, 109) # 아래것 보다 좋음 (x)
calc_contrib_mod(110, 110, 110, 110) # 기준
calc_contrib_mod(110, 110, 109, 109)
calc_contrib_mod(110, 110, 108, 108)
 
calc_contrib_mod(110, 110, 110, 111) # ※ 입력이 잘못된 케이스.
calc_contrib_mod(110, 110, 110, 112) # ※ 입력이 잘못된 케이스.
 
# 계산검증7 (x)
# 항목값이 가분수가 되면 결과값이 마이너스가 되는데
# 이것들이 기준값과 진분수인값들과 차이가 생긴다.
calc_contrib_mod(210, 110, 110, 1) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 2) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 99) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 100) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 101) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 102) # 아래것 보다 좋음 (o)
calc_contrib_mod(210, 110, 110, 109) # 아래것 보다 좋음 (x)
calc_contrib_mod(210, 110, 110, 110)
calc_contrib_mod(210, 110, 100, 110) # 위 보다는 안좋음
calc_contrib_mod(210, 110, 1, 110) # 위 보다는 안좋음
 
# -- 비교 (origin함수) (x)
calc_contrib_origin(210, 110, 110, 1) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 2) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 99) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 100) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 101) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 102) # 아래것 보다 좋음 (o)
calc_contrib_origin(210, 110, 110, 109) # 아래것 보다 좋음 (x)
calc_contrib_origin(210, 110, 110, 110)
calc_contrib_origin(210, 110, 100, 110) # 위 보다는 안좋음
calc_contrib_origin(210, 110, 1, 110) # 위 보다는 안좋음
 
# 계산검증8. (o)
calc_contrib_mod(110, 210, 1, 110)
calc_contrib_mod(110, 210, 109, 110) # 위 보다는 좋음
calc_contrib_mod(110, 210, 110, 110) # 위 보다는 좋음
 
# origin 함수 확인
calc_contrib_origin(110, 210, 109, 110) # 위 보다는 좋음
calc_contrib_origin(110, 210, 110, 110) # 위 보다는 좋음
 
# 심1
calc_contrib_origin(110, 210, 109, 110)
calc_contrib_origin(210, 110, 110, 109)
 
# 산수 노트
at <- 50
bt <- 100
a <- 30
b <- 15
(at / bt) - ((at - a) / (bt - b))
(at / bt) - ((at - a) * (bt - b)^-1)
(2 - 3)^2
2^2 + -2*(2*3) + 3^2
(2 - 3)^-1
# a²-2ab+b² = (a-b)²