골 프로그래밍 – Goal Programming with Excel

골 프로그래밍은 제목만 봐서는 직감적으로 알기 어려울 수 있습니다.
최대한 목표에 가깜게 하는 조건을 찾아주는 선형최적화 방법입니다.
원래는 프로그래밍이나 별도의 최적화 도구를 사용하는데 최근에는 엑셀로도 많이 작업합니다.

첨부한 링크를 보시고 잘 따라해보면 어렵지 않습니다. 다른 포스트에서 자세한 설명을 하기로 하고 이 포스트에서는 간단한 개요만 설명드립니다.

이하 평어체로 씁니다.

개요

엑셀에는 해 찾기(solver, linear programming) 기능이 있다.
선형계획법(Linear Optimization)을 엑셀로 구현한 것이다.
하지만 단순 선형계획법은 단일 타겟에 대한 최적화만 할 수 있기 때문에 다중 타겟을 최적화하기 위해서는 목표계획법(goal programming)을 사용해야한다.

목표 계획법 (Goal Programming) 또는 MLOP (Multi Linear Optimization Programming)

difference 값을 추가 도입해서 여러 개의 목표함수를 하나로 만든다.
그 후 그 하나의 함수를 최소화하는 최적조합을 simplex 알고리즘으로 찾아낸다.

엑셀 및 코드

엑셀로도 goal programming을 할 수 있는 것으로 알려져 있다.
엑셀로 goal programming을 시도해서 각 조건에서 최적 선택이나 최적 점을 찾는데 사용한다.
이후 Python 또는 R로 코드로 포팅할 수 있다.

쓸모

  • “비융율과 전환율을 각각 최대로 맞출 수 있는 rqs 또는 cic의 연속 노출 지점을 찾으라” 같은 것
  • 내가 돌봐주는 광고주에 impression-capping을 하려고 한다. ci_c 값은 얼마가 최적값(optima)일까?
  • 새로 들어온 광고주의 일예산은 얼마가 적당할까?

참고자료

잘 설명된 슬라이드를 참고한다.

https://sceweb.sce.uhcl.edu/helm/SENG5332DecisionAlysys/my_files/TableContents/Module-13/ch07.ppt

프론트에서 활용하기

Excel로 할 수 있으면 R과 Python, Javascript를 이용해서도 “Goal programming”을 할 수 있다.

최적값 찾는 기능을 서비스에 넣거나 배치 프로세스에서 자동으로 설정하게 할 수 있다.

따라해보기

단순 “해 찾기” Linear programming

“해 찾기”를 먼저 해본다. (“Goal programming”이 아님)

이것은 매우 쉽다. (바보가 아니면 다 할 수 있다)

cost_rate와 roas를 7:3의 가중치로 최대화하는 rqs의 연속 선택 시퀀스를 30개 이내에서 찾으라. 단 선택을 한다면 rqs=0부터 시작해야 한다.

local target 계산은 가중조화평균(아무짝에도 쓸모 없는 것이지만 테스트해본다)

패널티 트릭 Penalty trick

골 프로그래밍의 핵심은 패널티를 주기 위해 선형식 디자인을 어떻게 하는 가 이다.

연습을 해보지 않으면 디자인하는 것이 매우 헷갈리기 때문에 디자이닝에 대한 훈련이 되어 있어야 하고 고민도 깊이 해야 한다.

CTR이 높고 CVR이 낮은 것과 CTR이 낮고 CVR이 높은 것 중 어느 것이 좋은가?

광고 캠페인을 운영하다보면 비슷한 또는 동일한 캠페인인데 매체 또는 DSP업체 성과가 다음과 같이 다른 경우가 있습니다.

  • CTR은 높지만 CVR이 낮은 것
  • CVR은 높지만 CTR이 낮은 것

CTR과 CVR은 단순하게는 DSP의 타겟팅 능력과 매체의 품질에 가장 큰 영향을 받습니다만
그럼에도 불구하고 둘 중 어느 것이 좋은가를 기술적으로 볼 때

  • 광고업체(매체와 DSP모두)의 입장에서는 1번이 좋습니다.
  • 광고주의 입장에서는 2번이 좋습니다.

아직도 광고비 과금을 CPC(클릭당 과금) 방식으로 많이하기 때문입니다. 클릭율이 높으면 과금율이 높아지므로 매체( CPC매체인 경우)와 광고회사에게 좋습니다.

하지만 여기에 생각할 부분이 더 있습니다.

CPC가 만약 가변인 경우입니다. 즉 몇몇 광고 업체처럼 가변 CPC로 KPI에 따라 목표치에 최대한 근접하게 광고를 운영한다고 하면 생각할 것이 많아집니다.

CTR이 낮아도 광고요금이 상대적으로 높을 수 있고 CTR이 높아도 광고요금이 낮을 수 있습니다. 즉 CTR만으로는 광고의 성과를 정확하게 알아낼 수 없습니다.

결국 cVR로 마찬가지가 됩니다. 클릭 후에 오디언스의 액션에 따라 전환되는 비율을 측정하는데 CVR이 조금 낮더라도 전환수가 많다면 CVR이 높아도 전환수가 많지 않은 것 보다는 좋습니다.

CPC가 만약 고정이라면

그래도 CTR이 높은 경우가 사실은 더 유리합니다.

CVR은 원래 CTR보다 높게 형성되지만 보통 물건의 품질, 가격경쟁력, 브랜드파워에 따라 달라집니다. 그럼에도 불구하고 cTR이 높아져서 전환수가 많아지는 것이 전환률이 높은 것보다는 광구주 측이의 매출이나 이윤이장에서는 유리합니다.

결론

많은 경우에 CTR이 높고 CVR이 낮은 것이 더 좋습니다. 그 반데의 케이스보다는 유리합니다. 하지만 항상 그런 것은 아닙니다.

쉽게 이해하는 XGboost

요약

XGboost는 기계학습에서 사용하는 결정 트리(Decision Tree)라는 계열의 알고리즘 중 하나입니다. 중요한 특징으로는 분산 컴퓨팅으로 기계학습 모델을 빌드 할 수 있습니다.

즉 어려대의 서버로 대량의 학습데이터를 사용해서 결정트리 기계학습 모델을 만들 수 있게 해주는 기계학습 프레임워크(알고리즘)입니다.

결정 트리 (Decision Tree)

결정나무라고도 번역하는데 이게 느낌이 너무 이상해서 대부분 디씨젼트리 또는 결정트리라고 부릅니다.

결정트리 (Decision Tree)의 계보는 CART부터 시작해서 밑에 그림과 같습니다. 뒤에 LightGBM아 몇개가 더 있습니다만 XGboost까지의 계보는 저렇습니다.

여기서 아마 역사적으로 가장 잘 알려진 것은 “랜덤포레스트”일 것입니다.

랜럼포레스는 결정트리에 배깅 기법을 추가한 것이고
GBM은 결정트리에 부스팅 기법을 추가한 것입니다.

GBM은 분류 알고리즘이라면 어떤 알고리즘이라도 사용할 수 있지만 결정트리가 가장 쓰기 편하고 좋기 때문에 GBM은 결정트리를 주로 씁니다.

XGBoost: A Scalable Tree Boosting System

개요

  • XGBoost = eXtream Gradient Boosting
  • Gradient Boosted Decision Tree의 분산 컴퓨팅을 위한 새 구현체
  • 정확히 설명하면 GBM(Gradient Boosting Machine)의 분산 환경을 구현체

잘 알려지지 않았지만 GBRT (Gradient Boosting Decision Tree)는 정말 성능이 좋은 알고리즘이지만 모델 빌드속도가 매우 느리고 분산 노드를 이용해서 빌드 속도를 단축시키는 것이 가능하지 않다는 문제가 있습니다. GBRT는 정확도를 쥐어짜듯이 끌어내면서도 과적합(오버피팅)이 심하게 되지 않는 장점이 있습니다.

GBRT의 문제점은 학습데이터가 많아지고 자질(feature)가 많아질 수록 빌드속도가 늘어나고 한대의 컴퓨터에서 처리할 수 없는 메모리를 사용해야 하면 빌드를 하지 못합니다.

XGboost는 그 문제를 해결해놓은 것입니다.
이 문제를 해결했기 때문에 GBRT를 이용해서 대량의 학습데이터로 성능을 최대한 뽑아내는 모델을 빌드할 수 있게 되었습니다.

논문 Paper

읽어보면 좋습니다만 좀 어렵습니다.
https://arxiv.org/abs/1603.02754

유용한 정보

XGboost는 monothonic 제약을 지원합니다. 예측값이 항상 과거 보다는 미래의 값이 크거나 같아야 하는 경우를 말합니다.

사용상 문제 Issue

아직 몇 가지 문제도 있고 그렇습니다만 일반적으로 쓰는 데는 큰 문제가 없습니다.

그리고 카테고리 변수를 사용하지 못하는 큰 문제가 있습니다.

참조

다른 자료들도 참조하세요.

https://brunch.co.kr/@snobberys/137

LightGBM

LightGBM은 결정 트리(Decision Tree) 계열의 알고리즘 중에서는 현재까지의 가장 좋은 알고리즘입니다. 그렇다고 해서 이 알고리즘이 xgboost나 gbdt에 비해서 항상 성능이 좋다는 말은 아닙니다.

마이크로소프트(Microsoft)에서 만들었습니다.

GBM은 Gradient Boosting Machine의 약자이고 Light는 가볍고 빠르다는 뜻입니다.
그러면 “GBDT (GBRT)나 XGboost는 무겁운가?” 라고 묻는다면.

네. 그렇습니다. 하지만 XGBoost가 쓸모 없다는 말은 아닙니다.

lightGBM의 대략의 특징입니다.

특징

  1. 범주형 변수를 차원으로 올리는 더미 변환 또는 피폿(캐스팅)을 하지 않아도 된다.
  2. XGboost 보다 적은 데이터로 더 정확한 모델을 만들 수 있다.
  3. XGboost 보다 더 모델 빌드가 빠르다.

기존의 다른 알고리즘의 문제점과 개선한 방법

  • 느린 모델 빌드 속도
    • GBDT(Gradient Boosted Decision Tree; 또는 GBRT) 계열은 직렬 연산 알고리즘으로 병렬처리가 불가능하다.
    • GBDT는 엔트로피 계산(Information gain)을 위한 변수의 구간 탐색이 매우 빈번하다. 
    • 여러 개의 트리가 필요하지만 Gradient boosting(그래디언트 부스팅)을 하기 위해서는 병렬 처리를 할 수 없다. 어차피 트리를 병렬로 생성할 수 없기 때문에 가능하지 않다.
  • 모델 빌드 속도 개선 방법1
    • XGboost와 같이 변수에 대해서 히스토그램 색인을 만들고 학습 데이터를 병렬 분산, 중복 적재해서 연산력을 위해서 데이터 탐색 속도를 줄인다.
    • 즉 병렬처리를 하지 못하므로 직렬 처리에서 시간 소모가 가장 많은 부분에 연산자원을 과투입하고 데이터 전처리를 해둔 뒤 빌드 시간을 줄인다.
  • 모델 빌드 속도 개선 방법2
    • 학습데이터를 샘플링하는데 Gradient가 급격한 구간의 데이터들의 샘플 수를 줄이고 완만한 구간의 샘플을 늘려서 샘플의 능력 발현을 최대로 활용한다.
  • 범주형 변수 지원의 문제점
    • XGboost가 범주형 변수를 지원하지 못하기 때문에 문제가 많은데 범주형 변수를 지원하기 위해서 어쩌고저쩌고 하는 알고리즘(알고리즘이 매우 어려워서 여기서는 이름도 쓰지 않겠음)을 개발해서 적용했다.

장점

  • 매우 큰 학습데이터를 빌드하는데 시간 소모가 드라마틱하게 줄어들지만 예측 성능은 떨어지지 않는다.
  • 범주형 변수를 지원한다.
  • 사용하기 매우 편하다.
  • Microsoft가 만들었다.

단점

  • GPU로 추가 성능 개선을 할 여지가 없다.
  • Tensorflow를 비롯한 여러 프레임워크중에서 지원하지 않는 것이 많다.
  • 범주형 변수의 오토 레이블링(레벨링)을 지원하지 않는다. 범주형 변수를 모두 integer로 변환해야 한다.
  • Microsoft가 만들었다. 그래서 관리를 잘 해줄 것이라는 기대와 믿음이 있다.

Python패키지가 있으므로 주피터노트북에서 불러써도 됩니다.

Centos에 C++을 위한 build-essential 설치하기

Python 패키지 중에는 설치할 때 C++ 작성된 코어 모듈을 컴파일해서 설치하는 것들이 종종있습니다. 이런 것을 설치하려면 C++ 컴파일을 할 수 있는 컴파일러와 빌드도구를 설치해줘야합니다.

Ubuntu에서는 C++ 컴파일러를 포함해서 여러가지 개발 도구를 설치할 때 다음과 같이 합니다.

sudo apt-get install build-essential

Centos는 다음과 같이 하면 됩니다.

sudo yum groupinstall 'Development Tools'

MAB (Multi Armed Bandit) – 광고 플랫폼의 캠페인 노출 최적화

엠에이비, 멀리암드밴딧이라고 부릅니다.

“팔 여러 개 달린 산적” “Multi Armed Bandit”은 슬롯머신의 별명입니다.

이름처럼 “어떤 슬롯 머신의 팔을 당겨야 돈을 딸 수 있는가?” 와 같은 문제를 풀기위한 방법입니다.

이 알고리즘은 강화학습의 일종으로 봐주기도 하는데 엄밀히 말하면 강화학습에 넣지는 않습니다.

하지만 상당히 간단하고 쓸만하고 강화학습의 개념을 익히기 좋기 때문에 강화학습을 설명할 때 가장 먼저 설명하는 것이기도 합니다.

이 문제의 전제 조건이 있는데 한 번에 하나의 슬롯머신의 팔을 당길 수 있다는 것입니다.

그래서 동시에 모든 슬롯머신의 팔을 당겨서 그리고 여러번 당겨서 어떤 슬롯머신이 돈을 딸 학률이 높은지 알아낼 수 없습니다.

그래서 한 번에 하나씩만 선택해서 돈을 최대한 많이 따는 것이 이 문제의 푸는 목적입니다.

복잡한 공식은 여기에 안 적겠습니다. 구글에서 찾아보시면 수식과 코드가 다 있습니다. :D

첫번째 방법. Greedy 욕심쟁이

모든 슬롯머신에 순차적으로 한 번씩 팔을 내려봅니다. 그래서 돈을 못땄다면 다시 한 번씩 다 팔을 내려봅니다.

몇번을 수행한 후에 딴 돈이 가장 많은 슬롯머신에게 계속해서 몰빵합니다.

이게 Greedy 방식입니다.

단순하고 조금 무식한 방법입니다.

두번째 방법. epsilon

Greedy 방법을 사용하되 무작정 사용하지 않고 랜덤으로 팔을 당길 확률을 정해놓습니다.

만약 50%의 확률로 랜덤을 고르겠다고 하면 한 번은 지금까지 가장 돈을 많이 딴 슬롯머신을 당기고 한 번은 랜덤으로 아무것이나 고르는 방법입니다.

그나마 다른 것들에게 기회를 준다는 것 때문에 낫습니다.

epsilon이라는 이름은 랜덤으로 고를 확률값을 epsilon이라고 이름을 붙여서 부르기 때문입니다.

세번째 방법. UCB(Upper-Confidence-Bound)

위의 epsilon에서 약간의 공식을 주어서 랜덤 찬스가 왔을 때

무조건 랜덤으로 어떤 슬롯머신을 팔을 다기지 않고

덜 뽑혔던 슬롯머신에 가중치를 두어서 더 뽑아서 팔을 내려줍니다.

네번째 방법. Tompson sampling

톰슨 샘플링은 설명을 하면 조금 복잡해지는데 확률 분포 중 하나인 베타분포를 이용해서 확률이 가장 높은 것을 선택하는 것입니다.

베타분포 함수에 선택된 횟수와 돈을 딴 횟수를 입력하면 베타분포를 각각 구할 수 있고 그 베타분포를 확률 분포로 이용해서 값을 구하면 선택할 것을 찾을 수 있습니다.

저장된 데이터를 이용할 수 있는 장점이 있고 UCB 보다 성능이 조금 더 좋아서 온라인 추천 시스템에서 많이 이용되고 있습니다.

A/B 테스트와 MAB의 관계

A/B 테스트는 통계학의 실험계획법 중 하나 인데 2개 또는 2개 이상의 그룹을 동일한 수(최대한 비슷한 수) 만큼 각각 분할해서 한쪽에만 다른 처리를 해서 두 그룹의 차이를 보는 방법입니다

온라인에서는 흔히 버킷테스트라고 하는 방법입니다.

예를 들어 광고배너가 있는데 원래 배너는 테두리가 하얀색인데 테두리를 빨간색으로 바꿨을 때 사람들이 어떤 것을 클릭을 더 많이 하는지 알아 보고 싶을 때 같은 경우에 합니다.

A/B 테스트가 오랫동안 사용한 방법이기 때문에 잘 알려져 있지만 문제는 두 그룹을 방해받지 않게 불한하는 방법이 상당히 어렵고 두 그룹의 차이를 알아보는 방법이 데이터의 양상과 원래 데이터의 특성에 따라 여러가지 통계적인 방법을 써야하는 데 실수로 잘못된 방법으로 확인을 했다고 하더라도 그 실수를 알아내기 어렵다는 문제가 있습니다.

A/B 테스트를 하는 것은 많이 어렵지 않지만 A/B테스트의 결과를 해석하는 것은 매우 숙련된 통계학자가 필요하고 시간도 많이 걸립니다.

그래서 A/B 테스트를 하지 않고 각각 반응을 그대로 볼 수 있는 어떤 환경이 있다면 그 환경에서는 각각 매번의 결과에 따라서 결과가 좋은 것에 점수를 더 줘서 그것을 선택하게 만드는 방법을 쓰자는 것입니다.

그래서 MAB는 온라인 시스템의 추천시스템이나 평가에 굉장히 적합합니다.

광고시스템과 MAB

한 번에 5개의 제품을 동시에 보여지는 광고 이미지가 있다고 가정합니다.

사용자 별, 또는 사용자 그룹별로 어떤 제품에 더 관심을 가지는 지를 보고 클릭을 많이 하는 제품을 MAB에 의해서 더 많이 노출한다고 하겠습니다.

흔히 쓰는 방법이지만 이게 문제가 좀 있습니다.

  • 선택할 제품이 매우 많은 경우에는 못합니다. 아마도 제품의 카테고리가 있고 그것들 중에 가장 잘 팔리는가 하는 전략을 취할 수 있지만 상식적으로 좋은 방법은 아닐 것입니다.
  • 선호도는 계절성 효과, 요일 효과, 캠페인에 피로도에 따라 달라집니다. 슬롯머신 처럼 확률이 안변한다는 가정을 두기가 좀 어렵습니다. 변동이 너무 많습니다.
  • 또 가중치를 변경하는 것 때문에 생기는 문제가 파생적으로 생기는데
    • 쿠키로 인해 신규 및 재이용자의 분포에 영향을 미칩니다.
    • 변화에 대한 적응이 느리기 때문에 인해 관성때문에 결과가 왜곡될 수 있습니다.

아주 단순한 경우에만 사용이 가능하며 복잡한 시스템으은 오히려 결과를 왜곡할 수 있습니다.

저렇게 선택한 것이 여전히 가장 좋은 방법 또는 그리 좋은 선택이 아닐 수도 있겠지만 그 자체를 확실하게 확인 못합니다. 이건 다른 알고리즘도 동일한 문제이긴 합니다만.

티스토리(Tistory) 카테고리 체계

카카오(옜날 다음)에서 운영하는 블로그 플랫폼 티스토리에는 간단한 카테고리가 체계가 있습니다.

이 카테고리 체계는 블로거별로 설정을 하게 되어 있는데 복잡하지는 않습니다.

이런 체계를 보면 콘텐트를 어떻게 관리하는지 확인하는데 도움이 됩니다.

티스토리는 카테고리가 단촐한 것 같습니다. 2단계 분류 체계를 가지고 있는데 2단계 분류 체계를 가진 것 치고는 많은 편은 아닙니다.

쓸모가 있을지는 모르겠지만 그냥 올려봅니다.

라이프, life
- 일상다반사
- 해외생활
- 연애·결혼
- 육아
- 생활정보
- 반려동물
- 취미
- 사진
- 요리
- 자동차
- 인테리어
- 패션뷰티
- 건강
- 군대
여행·맛집, travel
- 국내여행
- 해외여행
- 캠핑·등산
- 맛집
- 카페·디저트
문화·연예, culture
- TV
- 스타
- 영화
- 음악
- 책
- 만화·애니
- 공연·전시·축제
- 창작
IT, it
- IT 인터넷
- 모바일
- 게임
- 과학
- IT 제품리뷰
스포츠, sports
- 스포츠일반
- 축구
- 야구
- 농구
- 배구
- 골프
시사, current
- 정치
- 사회
- 교육
- 국제
- 경제
- 경영·직장
이벤트, event

pycurl 윈도우 버전 설치하기 – install pycurl on Windows

Python 패키지 중에는 설치할 때 C/C++ 소스를 빌드해서 설치하는 것들이 있는데 이런 패키지들은 Windows에서 설치할 때 잘 안되는 경우가 많습니다.

빌드 시스템을 다 설치해야 하고 설치하고 난 후에도 설정을 맞추기가 어렵습니다.

특히 Linux에만 지원하는 특정 패키지를 사용해서 의존성이 높은 것들은 더더욱 그렇습니다.

이런 패키지 중에 비공식적으로 Windows용을 지원하는 사이트가 있습니다.

Pycurl도 설치가 가능합니다. 자신의 Python버전과 아켜텍쳐에 맞는 것을 선택해서 Windows에 있는 pip로 설치하면 됩니다.

https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl

R언어 개발툴 제작사 Rstudio 회사이름을 Posit으로 변경하다

Rstudio는 R언어 개발툴 이름이며 제작사의 이름이기도 합니다. Rstudio에는 R언어의 고수들이 모여 있는 많은 데이터과학자 겸 개발자들로 구성된 실리콘밸리에 있는 회사입니다.

R언어의 발전에 큰 영향을 준 회사이기도 합니다.

Rstudio를 비롯해서 GGplot2, Shiny, Rmarkdown, Tidyverse를 비롯한 패키지를 개발자와 부속 개발툴을 지원하고 있으며 이 도구들은 많은 데이터사이언티스가 주력으로 사용하고 있는 도구이기도 합니다.

코로나19로 전세계적으로 이름을 모르는 사람이 없게된 파이자(Pfizer)의 과학자들도 이 도구들을 주력으로 사용하고 있을정도입니다.

하지만 최근의 AI와 딥러닝의 발전과 함께 통계분석의 인기가 시들어가고 Python으로 데이터분석, 통계까지 하려는 움직임과 R언어를 배우려는 사람들이 줄어들면서 시장에서의 위상이 예전만 못하게 되었습니다.

Rstudio가 Python언어를 지원한지 오래되었습니다. 이제 R언어 하나만을 지원하는 것보다는 데이터과학이라는 분유 전체를 아우르는 개발툴과 부속 도구를 판매하고 교육하는 회사로 나가려고 하는 모양입니다.

바뀌는 것은 없습니다.

Rstudio workbench는 기본판은 여전히 무료이고 아직까지도 최고의 R언어 개발환경입니다.

Ubuntu 22.04에 Jenkins 설치하기

Ubuntu 22.04에 Jenkins를 설치하면 실행이 잘 안됩니다.
우분투 22.04는 최신 LTS 버전이라서 정말 쉽게 되야 할텐데 이상하죠?

Ubuntu 22.04에서 젠킨스가 안되는 이유는 대부분 Java때문입니다. Jenkins는 openjdk-11에서만 작동합니다. 설치해주고 기본 설정도 바꿔줘야 합니다. openjdk-18 같은 상위버전과는 작동하지 않습니다. Jenkins는 JVM기반의 Groovy 언어로 만들어졌습니다. JDK 영향을 많이 받으므로 이 점을 주의해야합니다.

설치 코맨드를 참고하세요.

# 자바 설치
sudo apt-get install openjdk-11-jdk-headless
# 기본 자바를 openjdk-11로 설정
sudo update-java-alternatives --set java-1.11.0-openjdk-amd64
# 키 받기
sudo wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
# 레파지토리 등록
echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list
# 젠킨스 설치
sudo apt-get install jenkins

메타 (페이스북, 인스타그램)이 정보제공동의 서명을 받는 이유에 대해서

페이스북, 인스타그램은 메타의 소유입니다. 메타는 페이스북이 회사명을 바꾼것이구요.

메타가 최근 자사의 소셜플랫폼에서 사용자에게 정보제공동의 서명을 받고 있습니다.

왜 그럴까?

페이스북과 인스타그램의 주 수익은 광고수입입니다. 광고 수익을 내기 위해서는 사용자의 트래킹 정보가 필요한데 이것은 웹브라우저는 쿠키, 안드로이드앱은 ADID, 애플 IOS는 IDFA를 사용합니다.

웹브라우저의 쿠키로 사용자의 트래킹 정보를 제고하는 것을 3rd party cookie 제3자쿠키라고 합니다. 이 제3자 쿠키를 이용하면 사용자의 트래킹 정보를 페이스북 외부와 내부에 연동해서 추적할 수 있습니다.

사용자가 쇼핑몰에서 본 노트북이 있다면 페이스북에 접속했을 때 그 노트북이 광고로 보이거나 하는 것입니다.

그런데 이게 3자 쿠키와 사용자 트레이싱이 점진적으로 사라지게 되는데 제3자 쿠키는 2023년 말로 크롭라우저에서 차단됩니다. 페이스북에서는 이걸로 인해 광고 노출을 하는 큰 수입이 사라지게 되므로 다른 대안을 찾아야 하는데 그건 사용자의 행적정보를 광고주에게 제공하는 것입니다.

해주면 어떤 일이 일어나는데?

그전에도 이런것을 어느정도 했었지만 정보제공동의 서명을방고 난 후에는 법적인 문제없이 본격저으로 할 수 있고 제3자쿠키나 ADID를 통한 사용자 트래킹이 사라지면서 손실이 발생하는 광고 수익을 대체할 수 있게 됩니다.

즉, 본인의 행적과 일부 데모그래픽 정보를 외부에 제공하고 어떤 형태로 그 댓가를 얻을 수 있게됩니다. 그렇다고 해서 주민등록번호깥은 것이 유출되거나 하지는 않지만 사는 지역, 성별, 연령대, 가입한 그룹들을 통한 성향, 취미, 친구관계를 통한 사회적 지위, 직장, 소득, 쓰는 글 등을 이용한 성향 분석 등으로 정리한 정보를 광고주에게 제공할 가능성이 큽니다.

페이스북 쿠키를 차단하고 ADID를 리셋하면 되는거 아닌가?

페이스북에 로그인한 정보를 사용하기 때문에 쿠키를 차단하는 것과 상관없이 정보는 제공됩니다.

인스타그램도 동일합니다. 즉 트래킹 당한 정보를 제공하지 않고 싶으면 페이서북과 인스타그램에 로그인하지 않으면 됩니다.

페이스북, 인스타그램은 쓰면서 정보를 추적당하지 않는 방법은 없는가?

없습니다. 매체 또는 플랫폼을 쓰는 댓가로 행적 정보를 제공하는 것이고 그걸 기반으로 광고 수익을 얻는 것입니다. 플랫폼에서 광고를 보고 싶지 않거나 추적하는 것을 피하려면 그 플랫폼을 쓰지 않아야 합니다.

이런 구조는 구글, 네이버, 카카오 다음 모두 같습니다. 이들 모두 정보를 수집하고 있고 광고에 이용하고 있습니다. 추적당하지 않으려면 로그인하지 않으면 됩니다. 그럴 수 있다면 말이죠.

윈도우에서 폰트의 영문 이름 알아내기 – Finding the name of the English font in a TTF file

영문처리만 지원하는 소프트웨어에서 폰트를 사용하기 위해서는 TTF 파일 또는 OTF 파일의 영문 이름을 알아야 하는 경우가 있습니다.

이 영문 이름은 폰트관리자, 서체관리자, 폰트포지(FontForge)로 제대로 알아내기 어렵습니다.

Python 스크립트로 알아낼 수 있습니다. 다음의 스크립트를 실행해서 간단히 확인하세요.

import os
import sys
from matplotlib import font_manager

def main(font_path):
    if sys.platform == 'win32':
        font_list = font_manager.findSystemFonts()
        file_path = font_path
        font_attribute = font_manager.FontProperties(fname=file_path)
    return font_attribute.get_name()

if __name__ == '__main__':
    font_path = sys.argv[1]
    font_name = main(font_path)
    print(font_name)
    sys.exit(0)

리타겟팅(Retargeting) 나를 계속 따라다니는 광고

온라인 광고 기법 중에 리타겟팅(ReTargeting)이라는 것이 있습니다. 움직이는 타겟을 따라다닌다는 말인데 여기서 타겟은 인터넷 사용자를 말합니다.

자신이 한 번 본적이 있는 상품에 대한 광고를 계속해서 보여주는 광고입니다. 한 번 쯤은 목격했을 것입니다. 이거 신기해 보일 수 있지만 실상은 매우 간단한 것입니다.

어떻게 내가 봤던 물건을 나에게 다시 광고하는가?

간단하게 쿠키를 사용합니다. 제3자쿠키(3rd party cookie)라고 합니다.

예를 들어 웹브라우저로 A라는 회사의 노트북에 대한 정보를 접속해서 본다고 가정하겠습니다.

1. 웹브라우저로 그 상품에 대한 정보가 있는 페이지에서 광고회사(제3자)의 자바스크립트를 호출해서 사용자가 어떤 상품을 보고 있는지 누구인지 등의 정보를 넘겨주고 동시에 광고회사에서는 사용자의 브라우저에 식별이 가능하도록 쿠키를 심어 놓습니다. 이 때 광고회사는 여러군데일 수 있습니다. 동시에 한군데 일 수도 있고 10군데 일 수도 있습니다.

2. 사용자가 다른 웹사이트인 뉴스, 블로그, 커뮤니티 등에 접속하면 그 사이트들은 광고회사와 제휴를 하고 있을 수 있는데 구글, 페이스북, 네이버, 다음 그리고 특정 광고회사와 직접할 수도 있습니다.

이때 구글과 다음 등은 다른 회사에게 다시 광고를 또 중계해 주는 방식을 할 수도 있고 직접 광고를 할 수도 있습니다. 이간 복잡하니 지금은 설명을 건너 뜁니다.

어쨌든 광고를 제공할 수 있는 회사 중에 아까 1에서 쿠키를 심어 놓은 회사중 하나 또는 여럿이 있고 이 회사들이 광고를 내보내겠다고 응답한다면 그때 이 회사들은 사용자가 봤던 상품의 배너이미지를 화면에 보여줍니다.

이것이 리타겟팅입니다.

모바일에도 그러던데 대체 어떻게 하는 것일까?

모바일 윕브라우저를 사용한다면 동일한 방식을 씁니다. 모바일앱인 게임이나 다른애플리케이션에서 보이는 것은 ADID 또는 IDFA라는 스마트폰에 기록되어 있는 임의식별코드를 이용합니다. 이 코드는 스마트폰에 자동으로 부착되는데 변경하거나 막도록 설정할 수 있습니다.

원리는 쿠키와 동일한데 이 아이디를 블럭하면 아무 광고나 보이게 됩니다.

가는 곳마다 계속 따라다니는 것은 어떻게 하는 것일까?

광고회사는 여러 매체와 제휴를 맺습니다. 즉 여러분이 다니는 유명한 사이트들이 많은 광고회사와 제휴를 하고 있고 많은 광고회사에게 접속 정보가 전달됩니다. 가는 곳마다 따라다니는 것 처럼 보이는 것입니다. 하지만 외부 광고회사와 제휴를 하지 않은 사이트도 있기 때문에 그런 사이트에서는 적어도 따라다니는 광고는 보이지 않습니다.

막으려면 어떻게 하면 될까?

브라우저를 시크릿모드로 사용하거나 쿠키를 블럭시키는 보안 브라우저를 사용하면 따라다니는 광고는 잘 나오지 않습니다. 하지만 그 자리에 전혀 관련없는 엉뚱한 광고가 보이게 됩니다.

따라다니는 광고인 리타겟팅 광고가 보이지 않을 뿐이지 다른 기법의 광고나 무작위 광고는 여전히 보여집니다.

광고를 완전히 안보이게 할 수는 없을까?

광고를 불록하는 확장소프트웨어를 사용하면 되지만 완벽하게 막지 못하고 특정 사이트는 광고를 차단하는 경우 내용물이 안보이도록 해놓기도 합니다.

내 개인정보와 행적이 다 노출될까?

노출 안됩니다. 업체들끼리 데이터를 익명화하거나 그룹화해서 숨기도록 강제되어 있습니다.

개연의 행적을 알아내거나 개인정보를 알아내려면 업체들끼리 한통속으로 짬짜미를 해야 하는데 그러기가 어렵고 금융사, 포털사, 광고사, 매체 등이 일심 동체가 되어서 서로 정보를 교환하거나 제공해야 하는데 현실적으로 그렇게 못합니다.

행여 했다가 걸리면 정부의 처벌이 강력하며 작은 회사는 멸망하게 됩니다. 그래서 안합니다.

그리고 개인정보, 개인행적추적 등에 대한 규제가 점점 심해지고 있고 3rd cookie와 ADID는 이제 사라지게 될 운명입니다.

제3자 쿠키를 막을 수 없는가?

Mac/IOS의 사파리 브라우저에서는 이미 막혀 있습니다. 크롬과 크롬기반의 브라우저는 2023년 12월 31일 기점으로 제3자 쿠키를 쓸 수 없게 됩니다.

안드로이드의 ADID는 조만간 기본 설정이 정보제공이 자동 허용에서 비허용으로 변경될 예정입니다.

시스템 만들기와 기술적인 숙제

리타겟팅을 하기위한 기본 설계는 간단합니다. 리타겟팅의 문제는 비즈니스적인 문제와 서버비용입니다.

사용자의 universal id를 관리해야 하기 때문에 key-value NoSQL이 있어야 합니다.

나머지 부속 시스템은 살을 붙이면 됩니다.

트래킹태그와 광고송출은 견고한 자바스크립트를 작성해서 각각 심어두면 됩니다.

트래킹태그 호출과 광고호출을 받아줄 대몬을 각각 만들어야 하는데 AWS lamda같은 것을 쓸 수 있겠지만 네트워크나 비용문제로 인해 자체 서버로 구축합니다.

C++, Java, GoLang, Rust 등을 이용해서 만들면 됩니다.

왜 쉽게 못하는가?

위와 같이 하면 되지만 말은 간단하지만 시스템은 실상 살을 붙이고 고가용성 등을 보장하려면 많은 삽질이 필요합니다. 게다가 앞서 비즈니스적인 문제를 말했는데 매체와 광고주가 각각 자기 사이트에 Javascript 코드를를 심어줘야 하는 문제가 있습니다.

대량의 트래픽

수만개의 매체와 수만개의 광고주, 수천만개의 상품이 있다고 할 때 이 트래픽을 모두 처리하는 것도 숙제입니다. 트래픽을 받아줄 서버와 데이터를 저장할 빅데이터 처리를 위한 스토리지와 서버버가 필요합니다. 배보다 배꼽이 큽니다.

어떤 광고를 보여줄 것인가?

사용자가 가장 최근에 본 제품들. 그러니까 약 24사긴 이내에 여러 제품을 사용자가 살펴봐고 그 내역이 NoSQL에 기록되어 있다고 할 때 그 중에 어떤 것을 보여줄 것인가 하는 것입니다.

그냥 간단하게 가장 최근에 본 것을 보여주면 되겠지 싶지만 실상은 그렇지 않습니다. 어떤 상품의 광고를 보여주며 그 광고를 클릭하고 물건을 결국 사고야말지는 상황에 따라 사람에 따라 제품에 따라 제품 종류에 따라 브랜드에 따라 모두 각기 다릅니다. 이걸 잘 선택하는 것이 기술입니다.

깊은 얘기는 생략합니다.

Get “https://registry-1.docker.io/v2/”: proxyconnect tcp: tls: first record does not look like a TLS handshake

docker build를 하던 중에 이런 오류가 날 때가 있다.

서버가 방화벽 안쪽에 있고 외부 네트워크로 나가기 위해서는 proxy를 써야하는 환경에서 HTTP_PROXY를 지정하지 않았기 때문에 생긴다.

환경변수에 HTTP_PROXY를 적어주면 된다.

Get "https://registry-1.docker.io/v2/": proxyconnect tcp: tls: first record does not look like a TLS handshake

sudo: add-apt-repository: command not found

Ubuntu에서 패키지를 설치하다보면 패키지를 받아야 할 레파지토리를 추가해줘야 하는다 그때 add-apt-repository를 사용합니다.

그런데 제목과 같이 에러가 발생하는 경우가 있습니다.

에러

sudo: add-apt-repository: command not found

설치 방법

아래와 같이 software-properties-common 패키지를 설치해주면 됩니다.

sudo apt-get install software-properties-common

Ubuntu에서 Aerospike 제거 방법

Aerospike는 추가, 삭제가 빠른 SSD기반의 대용량 데이터를 처리할 수 있는 NoSQL입니다.

Schemaless(스키마 없는) NoSQL이라고 하지만 Schema의 변경이 아주 자유롭지는 않습니다.

제거가 조금 까다롭습니다.

설치 방법

설치 방법은 아래의 문서를 보고 따라서 하면 됩니다.

https://docs.aerospike.com/server/operations/install/linux/ubuntu

제거 방법

제거 방법은 아래의 문서를 참조하면 되는데 아래에 명령어 세트를 적어 두었으니 그걸 참고해서 지워도 됩니다.

https://discuss.aerospike.com/t/how-to-remove-and-clean-up-an-aerospike-server-installation/4839

제거 코멘드

# 패키지 확인
sudo dpkg -l | fgrep aerospike

# 패키지 제거
sudo dpkg -r aerospike-tools
sudo dpkg -r aerospike-server-community

# 디렉토리 확인
sudo ls -al /etc/aerospike
sudo ls -al /opt/aerospike
sudo ls -al /var/log/aerospike
sudo ls -al /var/run/aerospike

# 제거
sudo rm -Rf /etc/aerospike
sudo rm -Rf /opt/aerospike
sudo rm -Rf /var/log/aerospike
sudo rm -Rf /var/run/aerospike

# 아래의 파일이나 디렉토리가 없어야 함
sudo ls -al /etc/init.d/aerospike
sudo ls -al /etc/logrotate.d/aerospike
sudo ls -al /usr/bin/aql
sudo ls -al /usr/bin/asadm
sudo ls -al /usr/bin/asbackup
sudo ls -al /usr/bin/asgraphite
sudo ls -al /usr/bin/asinfo
sudo ls -al /usr/bin/asloglatency
sudo ls -al /usr/bin/asrestore
sudo ls -al /usr/bin/asd
sudo ls -al /usr/bin/asfixownership
sudo ls -al /usr/bin/asmigrate2to3

엘라스틱서치 필드값으로 집계하기 ElasticSearch Aggregation Query (group by)

ElasticSearch는 RDMS가 아닙니다. DB가 아닙니다.

넓은 의미로는 데이터베이스라고 할 수는 있습니다. 데이터를 넣고 분석하고 삭제하는 등의 관리를 할 수 있으니까요. 하지만 RDBMS가 가진 많은 기능을 제공하지는 않고 그 중에 어낼리틱스 기능또한 제공되지 않는 것 중 하나입니다.

하지만 DB처럼 사용하려는 사용자 요구가 많고 엘라스틱서치 측에서도 계속해서 그런 어낼리틱스 기능을 지원하려고 하고 있습니다.

집계 쿼리(Aggregation Query)는 DB의 “group by”같은 것을 말합니다.

집계 쿼리를 사용할 때 주의할 것

  • 엘라스틱서치의 집계 쿼리는 부하가 심합니다.
  • 집계하려는 필드가 색인에 들어있지 않은 경우는 더 심합니다.

쓰고 싶으믄 크지 않은 인덱스에 대해서 하고 가능하면 대상 필드에 색인을 걸어 두는 것이 좋습니다.

쿼리 예제

aggregation 쿼리의 예제입니다. “createDate”라는 날짜 포맷의 컬럼을 기준으로 몇개의 문서가 있는지 집계하는 쿼리입니다. range는 날짜 구간입니다. 아래와 같은 형식으로 쿼리를 작성해서 응용해서 쓰면 됩니다.

{
    "query": {
      "range": {
        "createdDate": {
          "gt": "20220423",
          "lte": "20220523"
        }
      }
    },
    "aggs": {
        "group_by_state": {
          "terms": {
            "field": "createdDate"
          }
        }
    }
}

위와 같이 하면 집계 결과와 검색결과가 같이 나오는데 검색결과에 모든 필드가 포함됩니다. 필요 없는 것을 빼고 비교적 간략하게 받으려면 _source를 지정해주면 조금 더 낫습니다.

{
    "query": {
      "range": {
        "createdDate": {
          "gt": "20220423",
          "lte": "20220523"
        }
      }
    },
    "aggs": {
        "group_by_state": {
          "terms": {
            "field": "createdDate"
          }
        }
    },
    "_source": [
      "createdDate",
      "doc_id"
    ]
}

아예 hits에 결과를 안넣고 받으려면 size를 0으로 해주면 됩니다.

{
  "size": 0,
  "query": {
    "range": {
      "createdDate": {
        "gt": "20220423",
        "lte": "20220523"
      }
    }
  },
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "createdDate"
      }
    }
  }
}

tcpdump로 UDP 데이터가 어느 호스트에서 오는지 확인하는 법

제목 그대로입니다.

UDP는 TCP와 달리 커넥션(connection)을 맞는 방식이 아니기 때문에 바로 지금 데이터를 보내는 호스트들이 어떤 것인지 확인하기가 힘듭니다.

역시 tcpdump로 확인할 수 있습니다. 예를 들면 8125포트로 UDP데이터를 보내고 있는 호스트를 알아내려면 다음과 같은 코맨드를 실행하고 잠시 지켜보면 됩니다.

참고로 8125는 statsd가 데이터를 수신하는 포트이고 statsd는 시스템이나 애플리케이션의 상태를 모니터링하기 위해서 시그널 데이터를 받는 조그만 시스템입니다.

sudo tcpdump -i eth0 udp port 8125 -vv -X

Failure –
java.io.IOException: Downloaded file /var/lib/jenkins/plugins/workflow-support.jpi.tmp does not match expected SHA-1

젠킨스 플러그인 업데이트 도중에 다음과 같이 에러가 발생할 때 해결하는 방법이다.

Failure -
java.io.IOException: Downloaded file /var/lib/jenkins/plugins/workflow-support.jpi.tmp does not match expected SHA-1

플러그인 업데이트 주소를 아래와 같이 지정해준다.

https://updates.jenkins.io/update-center.json

The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY xxxxxxxxxxxxxxxx

우분투에서 apt로 레파지토리를 등록하고 설치를 할 때 이런 에러가 발생할 때가 있다.

특히 Jenkins

The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FCEF32E745F2C3D5

키 등록을 못한 것이라서 아래의 명령으로 된다. 아래의 키는 예시이므로 키는 자신의 것의로 바꾼다.

sudo apt-key adv --keyserver-options http-proxy=http://proxy.cns.widerlab.io:8080 --keyserver keyserver.ubuntu.com --recv-keys FCEF32E745F2C3D5

만약 서버가 외부 네트워크로 나갈 때 proxy를 사용해야만 한다면 위의 명령으로는 키가 등록되지 않는다. 다음과 같이 proxy를 지정해준다.

sudo apt-key adv --keyserver-options http-proxy=http://proxy.cns.yourproxy.com:8080 --keyserver keyserver.ubuntu.com --recv-keys FCEF32E745F2C3D5

이제 설치하려던 패키지를 설치하면 된다.

파이썬 한글 자모 분리 패키지

한글 자모분리를 하는 것은 오타처리, 스팸 감지, 욕설, 성적 표현을 주는 키워드 감지 같은 것을 하기 위해서 사용합니다. 몇 번 해보면 재밌지만 자모분리는 정작 뭐 좀 해보려고 하면 쓸데가 별로 없습니다.

Python에서 사용할 수 있는 한글자모분리 패키지 또는 코드 모음입니다.

파이썬 한글 자모분리 패키지 목록

– 한글툴킷: https://github.com/bluedisk/hangul-toolkit

– 한글유틸: https://github.com/kaniblu/hangul-utils

– 한글파이: https://github.com/rhobot/Hangulpy

– 파이썬 자모: https://github.com/JDongian/python-jamo

– 한글 자음/모음 분해 (코드): https://frhyme.github.io/python/python_korean_englished/

– 한글 유니코드 자모분리: https://nunucompany.tistory.com/28

대부분 주요 기능들은 모두 제공하고 있고 사용법도 쉽고 작동도 잘 됩니다.

원하는 것을 선택해서 쓰면 됩니다.

우분투에 Mecab 형태소분석기 설치 – Install Mecab in Ubuntu

우분투에 Mecab(은전한닢) 형태소 분석기를 설치하는 방법입니다.

Mecab 메카브 간략 설명

Mecab를 간단히 설명하면

  • Mecab은 C++로 만든 일본어 형태소분석기입니다.
  • Mecab-ko는 Mecab를 고쳐서 만든 한국어형태소분기이며 “은전한닢”라고 부릅니다.

예전 포스트가 있니 참고하세요.

MeCab 형태소 분석기, 형태소분석기란 무엇인가? 워드세그멘터와 형태소분석기

설치방법

Mecab-Ko는 Mecab 코어 모듈과 Mecab-ko-dic을 먼저 설치해야 하는데 번거롭습니다.

konlpy에 있는 간략 스크립트를 쓰면 쉽게 설치가능합니다.

sudo apt-get install curl git
$ bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh)

Mecab만으로는 형태소분석을 테스트하거나 활용하기 어려우니 Python 모듈도 설치해줍니다.

# python3.10은 아직 문제가 있으니 안전하게 조금 오래된 버전으로 간다.
# python3.10 -m pip install mecab-python3
python3.8 -m pip install mecab-python3

파이썬을 실행해서 테스트 해봅니다.

mecab = Mecab()
' '.join(mecab.morphs("무궁화꽃이피었습니다."))
# '무궁화 꽃 이 피 었 습니다 .'

E: Unmet dependencies. Try ‘apt-get -f install’ with no packages (or specify a solution).

우분투에서 패키지를 설치하다가 의존성이 깨지거나 하게 되면 그 뒤로 apt를 실행할 때 마다 에러가 발생합니다. 여간해서는 해결이 잘 안되는데요.

E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

이렇게 하면 됩니다.

sudo apt-get -o Dpkg::Options::="--force-overwrite" install --fix-broken

출처: https://askubuntu.com/questions/1044817/failed-installation-of-package-breaks-apt-get

[Jenkins] Could not initialize class org.eclipse.jgit.internal.storage.file.FileSnapshot

젠킨스로 git repository를 polling해서 코드가 푸시되었는지 확인한 후에 자동 빌드하는 프로세스를 만들면 로그에 이런 에러가 나면서 실패하는 경우가 있습니다.

Could not initialize class org.eclipse.jgit.internal.storage.file.FileSnapshot

젠킨스의 jgit 관련 클래스가 잘못된 것인데 이건 해결방법이 마땅치 않습니다.

그냥 Jenkins를 LTS가 아닌 최신버전이나 다른 버전으로 바꿔서 설치해야 합니다.

jenkins install Certificate verification failed: The certificate is NOT trusted. The certificate chain uses expired certificate. Could not handshake: Error in the certificate verification.

젠킨스를 설치하는데 지런 에러가 날 수 있습니다.

sudo apt update
sudo apt install jenkins

에러는 이렇습니다.

jenkins install Certificate verification failed: The certificate is NOT trusted. The certificate chain uses expired certificate. Could not handshake: Error in the certificate verification.

certification을 재설치해줘야 해결이 됩니다.

sudo apt install ca-certificates
sudo apt update
sudo apt install jenkins

우분투에서 R 설치하기

2022년 최신판입니다.

늘 똑같은데 최근에 설치하는 방법이 좀 바뀌었군요.

우분투 리눅스에 R을 설치하는 법은 거의 바뀌지 않기 때문에 https://cloud.r-project.org/ 에 방문해서 코드를 복사한 후에 같은 방법을 쓰면 늘 되지만 가끔 방식이 바뀌므로 방문해서 바뀐 것을 확인해봐야 합니다.

빠른 설치 방법

설명을 생략한 코드 복붙이 필요하면 아래의 순서대로 하시면 됩니다.

sudo apt update -qq
sudo apt install --no-install-recommends software-properties-common dirmngr
wget -qO- https://cloud.r-project.org/bin/linux/ubuntu/marutter_pubkey.asc | sudo tee -a /etc/apt/trusted.gpg.d/cran_ubuntu_key.asc
sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/"
sudo apt install --no-install-recommends r-base
R --version

한줄씩 따라가며 설치하기

복붙만 하다가는 바보가 됩니다. 어떤 순서로 설치하는지 알아둘 필요가 있습니다. 그래야 설치하다 문제가 생기면 어느 부분이 문제인지 알고 처리하는 법을 배울 수 있습니다.

시간이 없고 하기도 싫으면 굳이 지금 할 필요는 없습니다.

# 패키지 인덱스를 업데이트합니다.

sudo apt update -qq

# 헬퍼 패키지 2개를 설치합니다.

sudo apt install --no-install-recommends software-properties-common dirmngr

# 레파지토리 키를 설치합니다.

wget -qO- https://cloud.r-project.org/bin/linux/ubuntu/marutter_pubkey.asc | sudo tee -a /etc/apt/trusted.gpg.d/cran_ubuntu_key.asc

#  R 4.0 레파지토리를 등록합니다.

sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/"

# 설치합니다.

sudo apt install --no-install-recommends r-base

# 버전을 확인합니다.

$ R --version
R version 4.1.3 (2022-03-10) -- "One Push-Up"
Copyright (C) 2022 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
https://www.gnu.org/licenses/.

현재 시점에서는 R 4.1.3이 최신 버전이고 곧 새버전이 출시된답니다.

관련 포스트

우분투 18.04에 R 설치하기 – Install R on Ubuntu 18.04

우분투 18.04에 자바11 설치하기 – Install Java 11 onto Ubuntu 18.04

우분투 18.04에 자바11 설치하는 방법입니다.

18.04가 이제는 구버전이기도 하고 Java가 너무 구버전이 설치되어 있어서 업그레이드가 필요할 때가 많습니다. 보통 Java로 만들어진 애플리케이션들이 비교적 최근 버전의 자바를 요구하는 경우입니다.

설치하기

오픈JDK구버전을 제거합니다.

sudo apt-get remove openjdk*

오라클JDK도 제거합니다.

sudo apt-get remove oracle*

깔끔하게 청소해줍니다.

sudo apt-get autoremove --purge
sudo apt-get autoclean

openjdk 설치해야 하는데 커스텀 레파지토리를 추가하고 설치합니다.

sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt install openjdk-11-jdk

버전을 확인해서 11.x.xx 가 보여야 합니다.

java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.18.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.18.04, mixed mode, sharing)

파이썬으로 131072개 이상의 컬럼을 가진 CSV 읽기 – Python CSV – field large than field limit (131072) read csv

Pandas로 큰 CSV파일을 읽다보면 이런 에러가 나올 수 있습니다.
field larger than field limit (131072) read csv

즉 131072개의 컬럼까지만 읽을 수 있다는 것입니다. CSV의 컬럼이 131072개 이상이 있다는 것은 특이한 경우이긴 하지만 차원이 매우 높은 벡터 데이터가 있다거나 할 수 있기 때문에 실제로 이런 CSV파일이 없는 것도 아닙니다.

해결방법은 매우 간단합니다. csv.field_size_limit 함수로 시스템 최대치까지 늘려주시면 됩니다.

csv의 필드 크기 제한을 시스템 한계까지 늘려주면 해결할 수 있습니다.

import sys
import csv

csv.field_size_limit(sys.maxsize)

쉘스크립트 – 시작날짜와 끝날짜 사이의 모든 날짜출력

셀스크립트로 시작날짜부터 끝날짜까지 모든 날짜를 출력하는 코드입니다.

이런게 왜 필요할까 싶겠지만 생각보다 꽤 많이 필요하고 알아두면 편할 때가 많습니다.

보통 날짜별로 데이터를 프로세싱하거나 날짜별로 어떤 일을 처리하는 스크립트를 구간내의 모든 날짜에 대해서 실행하고 싶을 때 쓰거나 합니다.

예를 들면 일별로 배치프로세싱을 만들어서 집계를 하거나 예측이나 최적화 등을 처리하는 어떤 프로세스가 있다고 할때 이런 프로세스를 몇일분을 구간을 줘서 각각 일별로 처리하거나 할 때 말입니다. 이 코드를 알아두면 일별로 실행하는 배치프로세스를 수정하지 않고도 일별로 실행이 가능합니다.

쉘스크립트로 이런 것을 작성하기 어려운 편인데 사실 패턴을 알고 나면 그렇게 어렵지 않습니다.

핵심은 while 구문과 date 코맨드를 잘 사용하는 것입니다.

#!/bin/bash

begin_date="20220209"
end_date="20220410"

while ! [[ $begin_date > $end_date ]]; do
    echo $begin_date
    bash ./daily-batch-processing.sh $begin_date
    begin_date=$(date -d "$begin_date + 1 day" +%Y%m%d)
done

CUDA_ERROR_OUT_OF_MEMORY 에러

CUDA_ERROR_OUT_OF_MEMORY 에러

Tensorflow 작업을 하다보면 이런 에러가 보일 때가 있습니다.

보통 Jupyter notebook을 사용하는 서버 환경에 이런 에러가 보이는데

원인은 GPU를 사용하면서 GPU의 메모리를 할당받고 해제하지 않은 프로세스가 있거나 많기 때문입니다.

이 프로세스가 지금 실행하고 있고 중요한 것이 아니면서 Jupyter notebook으로 실행된 메모리 점유만 하고 사용하지 않는 것이라면 그냥 kill 하면 됩니다.

먼저 nvidia-smi로 GPU의 할당 내역을 보고 nvidia-smi –gpu-reset으로 해제를 시도합니다.

sudo nvidia-smi
sudo nvidia-smi --gpu-reset

하고 나서도 해제가 안된다면 킬 해줍니다.

sudo kill -09 24089

하고 나면 깔끔해진 것을 볼 수 있습니다.

이제 메모리 오류가 발생했던 코드를 다시 실행하면 더 이상 에러가 발생하지 않습니다.

선형대수와 데이터과학

데이터과학을 하려면 선형대수를 꼭 배워야할까?

데이터과학, 기계학습, 데이터마이닝, 인공지능, 통계 등에 항상 따라붙는 수학이 선형대수학입니다. 이와 관련된 채용 공고에도 선형대수학에 대한 기본 또는 충분한 이해가 요건으로 붙는 경우가 많았습니다.

데이터과학을 하려면 선형대수를 꼭 배워야 하나?

이 질문에 대한 대부분의 전문가들의 답은 “그렇다”일 것입니다.

어쩌면 여러분은 “데이터과학을 하는데 선형대수학은 필요없다”는 말을 듣고 싶어서 이 포스트를 보고 있는지도 모르겠습니다.

솔직히 누군가 그렇게 말한 사람이 있다면 그건 “개뻥”입니다. 또는 속성 과정으로 금방 배우고 마스터링 할 수 있다고 말한다면 그것도 “개뻥”입니다.

“얼마만큼 깊이 또는 많이 하느냐”의 차이는 있겠지만 선형대수의 기초 지식은 반드시 필요하며 데이터과학, 데이터분석, 통계, 기계학습, 데이터마이닝과 같은 데이터 관련 고급 기술을 배울 때 선형대수는 필수적입니다. 못하면 멍텅구리가 되거나 결국에는 아예 아무것도 이해하지 못하게 됩니다.

선형대수학은 무엇인가?

무시무시한 어감을 가진 선형대수는 대수학의 한 갈래로 영어로는 “Linear Algebra”이고 “리니어 앨지브라”라고 읽습니다. 발음이 조금 까다롭기 때문에 한국인들은 “선형대수” 또는 “선대”라고 읽습니다.

선형대수학이 무엇인지 쉽게 설명하면

선형대수는 짧게 말하면 벡터와 행렬을 다루는 수학입니다.

  • 벡터는 관련이 있는 숫자들을 묶어 놓은 것이고
  • 행렬은 벡터 여러 개를 묶어서 사각형 깍두기로 만들어 놓은 것입니다.

이렇게 모양을 만들어 놓는 것은 안 중요한데 이렇게 서로 뭔가 관련이 있는 숫자들을 묶어서 뭉치로 만들고 이것들을 서로 곱하고 나누고 빼고 줄이고 바꾸고 이것저것 하면 숫자와 숫자의 관계나 숫자 압축, 숫자 분해이 가능하고 문제를 풀 수 있는 경우가 많아집니다.

즉 선형대수학과 미적분을 사용하면 현실에서 정답을 찾는 것이 아니라 쓸만한 결과를 거의 항상 얻어낼 수 있습니다.

선형대수의 큰 매력은 대부분의 경우에 문제를 해결할 수 있다는 것입니다. 정답이 있다는 것이 아니라 “문제를 해결”한다는 것을 이해해야 합니다.

선형대수는 수학적으로 답이 없는 문제가 있을지라도 현실적으로는 억지로라도 답을 찾거나 가장 그럴듯한 것을 찾아낼 수 있습니다.

답이 없다고 포기할 것이 아니라 가장 그럴듯하고 가장 쓸만한 것을 찾아낸다면 그것이 답인 것인데 선형대수는 그런 것을 하는데 가장 도움이 되는 수학입니다.

왜 이름이 선형대수인가?

선형은 “선의 형태”라는 뜻인데 벡터와 행렬을 다룬다고 하면서 여기에 갑자기 “선”은 왜 나오는가?

선형대수가 있으면 원형대수나 곡형대수 같은 것도 있는가? 이런 의문도 들텐데요.

쪼금 어렵게 말하면 벡터를 다차원공간상에 매핑하고 이 벡터를 여러 연산으로 바꾸게 되면 이 벡터가 차원안에서 직선으로만 움직이기 때문입니다. 벡터는 공간상의 점이라고 하면 이 벡터는 직선운동만 가능합니다. 회전해서 움직일 수 없고 직선이 아니게 바꾸는 유일한 방법은 내적이라는 계산밖에 없습니다.

쉽게 말하면 벡터를 공간에 있는 점으로 표현해서 그림을 그려놓고 이런저런 계산을 해서 이 벡터를 다시 공간상에 점을 찍어 놓고 보면 직선으로만 움직이더라는 것이 이렇게 직선으로만 움직이게 해서 숫자로 부터 어떤 의미나 관계를 찾아내기 때문에 선형대수라고 합니다.

그래서 삼각형과 원의 관계를 다루는 삼각함수가 선형대수에서는 잘 보이지 않습니다. 물론 수학자들이 하는 고등수학에는 선형대수나 삼각함수나 뭐 이것저것 섞여서 빈번하게 나오지만 그건 그 사람들 알아서 할 일이구요.

데이터과학을 위해서선형대수를 꼭 배워하는 이유?

선형대수학을 모르고 데이터과학, 통계분석, 데이터마이닝, 기계학습, 인공지능을 한다면 어떤 알고리즘이나 방법(프레임워크나 스킴)의 원리를 이해하지 못하게 됩니다.

이해하지 못하면 다룰 수 없고 알고리즘같은 것이 압도당하고 지배당하게 됩니다.
샘플 코드 복붙해서 실행하는 것인 모델 빌드나 데이터 과학의 전부가 아닙니다.

간단한 예로 선형회귀(Linear Regression)에 대해서 얘기해보면

선형회귀는 처음보면 단순하고 쉬워 보이지만 기저를 다 이해하기 상당히 까다롭고 어렵습니다. 기본을 이해하지 못하면 결국 제대로 다루지 못하고 그 보다 더 복잡하고 난해한 알고리즘은 사용하지 못합니다.

선형회귀를 이해하기 위해서는 OLS를 알아야하고 그러려면 행렬연산이나 이것저것 선형대수와 미적분을 알아야합니다. 제대로 이해하지 못한채 경험적으로 암기한 내용으로만 선형회귀를 하고 나서는 엉뚱한 선형회귀 모델을 만들어 놓고 “이게 왜이러지?”하고 고민하는 경우를 많이 봤습니다.

숫자묶음에서 특징을 추출하는 특이값분해 같은 기법도 선형대수를 배우지 않으면 1도 이해하지 못합니다.

인공지능에서 숱하게 사용하는 경사하강(Gradient Desecnt)과 역전파(Back propagation)같은 것은 선형대수와 미적분의 컬래버입니다.

어떻게 배우면 될까? 문과도 가능할까?

선형대수는 대수학 중에서 매우 쉬운 수학 중에 하나입니다.

대수학들 (미적분, 선형대수학, 위상수학 등…)중에서 쉽다는 말이지 쉽다는 것이 절대 아닙니다.

문과든 이과든 이 선형대수학은 쉬운것 같지만 그렇게 쉽지 않습니다.

그렇다고 수포자가 못할 정도의 것은 아닙니다. 이것도 역시 사람이 만든 것이기 때문입니다.

선형대수학 공부를 쉽게 접근하려면

온라인 강의를 많이 들으면 좋습니다. 요즘 유튜브에 강의가 참 많이 있습니다. 하지만 시간이 많이 든다는 것을 알아야 하고 이해가 될 때까지 반복해서 듣거나 이해가 안되면 다른 강의를 찾는 것이 좋습니다.

가장 유명한 강의이고 추천할 강의는 길버트 스트랭 MIT 교수님의 선형대수학 강의이고 자막이 있습니다.

온라인 강의가 싫으면 결국 대학교재 중에 좋은 것을 하나 읽어야 하는데 “공업수학”교재를 찾으면 됩니다. 크레이그 공업수학 책이 가장 잘 알려진 편이지만 기초가 없으면 독학하기에 조금 어렵지만 못할 것도 아닙니다.

이런 책은 이해가 안되더라도 처음부터 끝까지 다 읽어야 좋은데 고등학교 이과 수준의 수학을 다 알고 대학에서 배우는 고등수학도 일부 알아야 한다는 점입니다.

늦지 않았을까?

늦었다고 시작했을 때는 늦은 겁니다.
하지만 더 늦으면 계속 늦어지기만 할 뿐입니다.
조금씩 하다보면 언젠가는 선형대수가 만만해지는 시기가 옵니다.
물론 이럴때가 또 위험하 시기이긴 하지만 말이죠.

중요한 것은 “지금부터 해도 나는 안될꺼야” 라는생각과 “책 한 권만 떼면 금방 마스터 할 수있을꺼야” 라는 생각을 버리는 것입니다.

파이썬 문자열에서 특수문자 제거하는 3가지 방법 – python 3 ways to remove punctuations from a string

Python으로 특수기호 제거하는 예제입니다.

자연어처리, 크롤한 데이터 정제 등을 할 때 특수문자를 제거하거나 클린징을 해야 할 때 많이 하는 작업입니다.

특히 비정형 데이터 중에서 텍스트(문자열)을 다루다보면 계속 해야 하는 그런 작업입니다.

짧게 먼저 요약하면

  • 가장 빠른 것은 translate() 메서드를 사용하는 것이고
  • 그 다음은 string.replace() 메서드를 사용하는 것이고
  • 가장 느린 것은 정규표현식을 사용하는 것입니다.

속도가 문제되지 않으면 (느려도 되면) 정규표현식을 사용하는 것이 가장 유연하고 좋습니다. 특정 문자를 넣고 빼거나 숫자를 포함하거나 하는 여러가지 작업을 할 수 있습니다.

3가지 방법의 소스코드를 참고하세요.

translate() 함수 사용하기

# strings 패키지의 translate() 함수를 사용하여 특수기호를 제거하는 예제
import string
input_string = '!hi. wh?at is the weat[h]er lik?e. !@##$%%^^&*)_+{}|?"'
output_string = input_string.translate(str.maketrans('', '', string.punctuation))
print(output_string)
# Returns: hi what is the weather like
# 제거되는 특수기호는 아래와 같다.
print(string.punctuation)
# Returns: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

정규표현식 regular expression 사용하기

# 정규표현식을 사용하여 특수기호를 제거하는 예제
import re
input_string = '!hi. wh?at is the weat[h]er lik?e. !@##$%%^^&*)_+{}|?"'
output_string = re.sub(r'[^\w\s]', '', input_string)
print(output_string)
# Returns: hi what is the weather like

# 좀더 빨리 하려면 정규표현식을 컴파일하는 것이 좋다.
pattern_punctuation = re.compile(r'[^\w\s]')
output_string = pattern_punctuation.sub('', input_string)
print(output_string)

string.replace() 사용하기

# string.replace() 함수를 사용하여 특수기호를 제거하는 예제
import string
input_string = '!hi. wh?at is the weat[h]er lik?e. !@##$%%^^&*)_+{}|?"'
for character in string.punctuation:
    input_string = input_string.replace(character, '')
print(input_string)
# Returns: hi what is the weather like

소스 파일

github에 노트북으로도 올려놨습니다.

https://github.com/euriion/python-exams/blob/main/remove-punctuations.ipynb

rsync – ‘cannot delete non-empty directory’ errors

로컬에 있는 파일과 모델, 데이터 등을 리모트의 어딘가로 싱크하는 것은 데이터사이언스 작업을 하면서 빈번하게 있는 일입니다. 복잡한 파이프라인을 작성할 것은 아니기 때문에 간단하게 rsync를 사용할 때가 많습니다.

제가 주로 사용하는 옵션은 이렇습니다.

rsync -avzrub --delete /tmp/source /tmp/target

그런데 이 옵션을 실행하다 보면 다음과 같은 에러가 나올 때가 있습니다.

rsync 'cannot delete non-empty directory' errors

–delete 옵션은 소스에 없는 것들은 타겟에서도 지우라는 명령입니다. 이때 소스에 없는 파일과 디렉토리는 타겟에서도 지워야 하는데 디렉토리를 지우지 못하는 것입니다.

원인은 -b 옵션 때문인데 -b 옵션은 타겟에서 파일을 지욱 때 만약을 대비하기 위해 파일을 ~가 끝에 붙은 이름으로 변경해서 백업하는 기능입니다. 이 옵션으로 인해 지우지 못하게 됩니다.

-b 옵션을 제거하면 문제가 해결됩니다.

만약 그래도 백업을 해야 하고 특정 디렉토리는 다르게 관리해야 한다면 –exclude 옵션으로 그 디렉토리를 제외하고 그 디렉토리는 다른 옵션으로 rsync를 수행해야 합니다.

Faiss – 고속 벡터 검색 엔진으로 유사도 검색하기, Vector Search Engine

Faiss는 Facebook Lab에서 만든 벡터 검색 엔진입니다.

Faiss는 벡터 갬색 엔진이고 유사도 검색을 하거나 추천, 기계학습로 만든 모델을 활용해서 응용 서비스를 만들 때 사용합니다.

별거 아닌거처럼 보이지만 불가능한 것을 가능하게 만들어 주는 매우 유용한 라이브러려입니다.

라이브러리이기 때문에 자체로 서비를 제공하는 것은 아니고 이 라이브러리를 이용해서 Backend, Frontend 서비스를 개발하거나 응용 프로그램에 넣을 수 있습니다.

벡터 검색 엔진

벡터 검색 엔진이 뭔지를 설명해야 하는데요. 보통 그래프 서치라고도합니다. 이것들은 주로 수치를 찾는 것을 말하는데 지도검색 같은데서도 사용하는 것으로 매우 쓸모가 많은 엔진입니ㅏㄷ.

일반적으로 검색 엔진이라고 말하면 흔히 텍스트를 검색하는 것을 생각합니다. 구글의 웹 검색, 네이버 검색, 다음 검색 같은 것은 검색 포털이요. 그게 아니면 Elastic Search나 Lucene갈은 검색 엔진을 생각할 텐데요.

하지만 벡터 검색은 텍스트가 아닌 벡터를 빠른 속도로 찾는 것을 말합니다. 벡터는 수열을 말합니다.

아래와 같이 10개의 숫자가 묶여 있으면 이걸 10차원 벡터라고 합니다. 숫자가 100개 있으면 100차원 벡터, 1000개면 1000차원 벡터입니다.

[-0.00709967 -0.01956441  0.03790117 -0.00150699 -0.02145613 -0.06128123
  0.04965064 -0.05588596  0.08241648 -0.05128423]

이런 것들이 수억개가 있고 수억개 중에 어떤 벡터와 가장 가까운 벡터를 찾아야 한다면 문제가 어려워집니다.

가장 가까운 것을 주어진 입력 벡터와 수억개의 벡터를 모두 하나씩 연결해서 서로의 거리를 계산한 다음 가장 가까운 것을 찾아야 하기 때문입니다.

가장 가까운 것을 찾는데 수십분이 걸릴 수 있습니다. 이러면 실제 서비스에서는 쓸 수 없습니다.

어떤 사용자가 온라인 서적 판매사이트에 접속했을 때 그 사람에게 책을 추천해줘야 하는데 추천할 책 목록을 검색하는데 10분씩 걸린다면 서비스에 적용하지 못합니다. 다른 서비스도 마찬가지구요.

Faiss는 인덱싱 방식을 다르게 해서 데이터가 많아도 짧게는 밀리초 단위 길게는 수초 이내에 결과를 찾아 줍니다. 즉 온라인 추천 서비스에 빠르게 적용하는 추천 시스템 등을 개발하는데 사용할 수 있습니다.

Python Faiss library

Faiss는 Python wrapper를 공식 지원하고 있습니다. c++로 만들어졌으니까 다른 언어로도 연결해서 사용할 수 있습니다. Go lang이나 Node.js, Kotlin 같은 것을 쓰면 Python 보다는 성능이 더 좋을 것입니다.

깃헙 레파지토리: https://github.com/facebookresearch/faiss

레파지토리에 있는 것을 설치해도 되고 그냥 pip를 이용해서 설치해도 됩니다.

pip3 install faiss-cpu

gpu 버전을 설치하고 싶으면 gpu 버전ㅇ로 명시해서 설치하면 됩니다.

pip3 install faiss-gpu

사용법은 매뉴얼을 봐야 하겠지만 기본 사용법은 쉽습니다.

Faiss로 유클리디안 거리로 벡터 검색하기

아래 코드는 유클리디안 거리(Euclidean Distance)로 찾는 예제입니다.

이런 것은 KNN (K-nearest-neighbor) 와 같은 기계학습 모델에 사용하는 것입니다. KNN은 판별 모델에서 사용할때 매우 강력한 알고리즘이지만 검색할 때 너무 느리고 자원을 많이 사용하는 문제로 인해서 실제로는 거의 사용을 못하는 알고리즘이지만 Faiss를 이용하면 이걸 쓸 수 있습니다.

Faiss 색인을 생성할 때 벡터의 차원을 지정해주고, Index의 유형도 결정을 해줘야 하는 것이 중요합니다. 검색은 입력한 k의 갯수만큼 리턴하게 되어 있고 벡터의 색인 번호와 거리를 리턴하게 되어 있늡니다.

색인 번호는 그냥 입력한 입력한 벡터의 순번입니다.

import faiss
import numpy as np
import random

# Euclidean distance 기반으로 가장 가까운 벡터를 찾는다.

# 랜덤으로 10차원 벡터를 10개 생성
vectors = [[random.uniform(0, 1) for _ in range(10)] for _ in range(10)]
# 10차원짜리 벡터를 검색하기 위한 Faiss index 생성
index = faiss.IndexFlatL2(10)
# Vector를 numpy array로 바꾸기
vectors = np.array(vectors).astype(np.float32)
# 아까 만든 10x10 벡터를 Faiss index에 넣기
index.add(vectors)
# query vector를 하나 만들기
query_vector = np.array([[random.uniform(0, 1) for x in range(10)]]).astype(np.float32)
print("query vector: {}".format(query_vector))
# 가장 가까운 것 10개 찾기
distances, indices = index.search(query_vector, 10)
# 결과룰 출력하자
idx = 0
for i in indices:
    print("v{}: {}, distance={}".format(idx+1, vectors[i], distances[idx]))
    idx += 1

Faiss로 코사인 유사도로 검색하기

유클리디안 거리(Euclidean Distance)로 가장 가까운 벡터를 찾으면 특정 차원의 양적 수치에 따라는 거리가 가깝다고 판별되는 편향의 문제가 있습니다. 이게 문제가 될 때가 있고 그렇지 않을 때가 있는데 이것은 문제의 도메인에 따라 다릅니다. 그러니까 문제가 주어진 환경에 따라 그때그때 다르다는 뜻입니다.

이런 문제를 피하는 방법은 유사도를 계산할 때 거리측정 방법을 유클리디안 거리를 사용하지 않고 코사인 유사도를 사용해서 벡터의 방향이 가까운 것을 찾는 것입니다. 보통 검색엔진들도 이 방법을 기본으로 사용합니다.

Faiss도 이걸 지원하는데 예제는 아래 코드를 보시면 되고 앞서 설명했던 유클리디안 거리 기반의 검색과 다른 점은 index를 생성할 때 타입을 다르게 생성해야 하고 벡터를 노말라이즈 해줘야 한다는 것입니다. 벡터가 이미 노말라이즈되어 있다면 안해도 됩니다.

import faiss
import numpy as np
import random

# 코사인 유사도 (Cosine Similarity) 를 이용해서 가장 가까운 벡터를 찾으려면 몇가지를 바꿔줘야 한다.
# 코사인 유사도 (Cosine Similarity) 를 사용하려면 벡터 내적으로 색인하는 index를 만들면 된다.
# 코사인 유사도를 계산하라면 벡터 내적을 필연적으로 계산해야 하기 때문이다.

# 랜덤으로 10차원 벡터를 10개 생성
vectors = [[random.uniform(0, 1) for _ in range(10)] for _ in range(100)]
# 10차원짜리 벡터를 검색하기 위한 Faiss index를 생성
# 생성할 때 Inner Product을 검색할 수 있는 index를 생성한다.
index = faiss.IndexFlatIP(10)
# 아래는 위와 동일하다.
# index = faiss.index_factory(300, "Flat", faiss.METRIC_INNER_PRODUCT)

# Vector를 numpy array로 바꾸기
vectors = np.array(vectors).astype(np.float32)
# vectors를 노말라이즈 해준다.
faiss.normalize_L2(vectors)
# 아까 만든 10x10 벡터를 Faiss index에 넣기
index.add(vectors)
# query vector를 하나 만들기
query_vector = np.array([[random.uniform(0, 1) for x in range(10)]]).astype(np.float32)
print("query vector: {}".format(query_vector))
# 가장 가까운 것 10개 찾기
distances, indices = index.search(query_vector, 50)
# 결과룰 출력하자.
idx = 0
for i in indices:
    print("v{}: {}, distance={}".format(idx+1, vectors[i], distances[idx]))
    idx += 1

노트북 코드

위 코드의 노트북은 깃헙 레파지토리에 올려 두었습니다.

https://github.com/euriion/python-exams/blob/main/faiss/faiss-exam.ipynb

다음 번에는 기회가 되면 Faiss를 이용한 간단하고 빠른 추천 엔진을 만드는 예제를 올려보겠습니다.

R로 스타벅스 지역별 매장수 분석, 데이터 크롤, 데이터 분석

R언어로 , 스타벅스 매장 데이터를 크롤해서 분석하는 간단한 예제 스크립트입니다.

전체 코드는 글 아래 쪽에 있습니다.

코드 설명

예제에서 하려는 것

간단하게 재미 삼아하는 토이(toy) 분석입니다. 실제 분석 프로젝트에서는 이 보다는 더 심도가 깊게 해야 합니다.

이 분석의 실제 목적은 R로 데이터 크롤을 해서 분석은 어떻게 하는 것인지 설명하는 것입니다. 분석 리포트에서는 크롤한 데이터를 이용해서 인사이트를 도출하고 탐색적데이터분석(EDA)를 어떻게 하는지 예제로 보여줍니다.

이 분석에서 해보려고 하는 것은 스타벅스의 매장 목록을 가져와서 각 시도별, 구군별로 어느 지역에 스타벅스 매장이 가장 많은지 어떤 인사이트가 있는지 살펴보고 또 지역별 인구수와 스타벅스 매장 수와 관계가 있는지를 확인해 보는 간단한 분석입니다.

분석에 들어가기 전에 상식적으로 식음료 판매 매장들은 유동인구가 많은 곳에 자리를 잡는 것이 일반적이기 때문에 당연히 지역별 인구수와 스타벅스 매장 수는 관련이 있을 것이라고 추측할 수 있습니다.

그래서 서울이라면 강남 지역에 스타벅스가 가장 많을 것이라고 추측해 볼 수 있습니다. 서울은 강남에 오피스가 가장 많아서 직장이들도 많고 유동 인구도 많습니다. 정말 그런지 확인은 해봐야 겠지요.

그래서 여기서 확인해 볼 가설은 “스타벅스 매장의 위치는 지역의 인구수 또는 유동인구와 관련이 있을 것이다.” 라는 것입니다.

너무 뻔한 것이어서 굳이 세심하게 분석할 필요가 없다고 생각할지 모르지만 하지만 이미 알고 있거나 너무 뻔한 사실도 실제로 그런지 확인하는 것도 유의미합니다.

의외성이 많아지는 요즘 세상은 알고 있던 상식이 실제와는 다른 경우도 많기 때문입니다.

먼저 알아야 할 것

이 포스트에서 하려는 것을 할 때 꼭 알아야 할 정보와 필요한 것은 3가지입니다.

  • 매장의 위치 데이터 제공처
  • 매장의 위치데이터 데이터를 크롤(스크랩)하는 법
  • 크롤한 데이터를 잘 정제, 정돈하는 법

R언어 사용법 등은 당연히 알아야 하는 것이라 목록에는 안 적었습니다.

Python이나 다른 언어로 해도 되지만 여기서는 R언어로 하겠습니다.

데이터를 얻어 오는 곳

이런 정보가 어디 있는지는 검색을 해서 알아내야 합니다. 검색해보니 대충 아래와 같은 것이 제일 만만해 보입니다.

먼저 스타벅스 매장 주소 데이터는 스타벅스 웹사이트에서 가져오면 되는데 csv나 엑셀 파일로 다운로드하게 지원하지 않으니 웹페이지의 내용물을 읽어서 파싱(parsing)해야 합니다.

이 작업은 웹 스크랩이라고 하는데 흔히 크롤이라고 부릅니다. 사실 원래 크롤과 스크랩은 서로 차이가 많습니다만 이 글에서는 그냥 널리 알려진 대로 크롤이라고 하겠습니다.

또 스타벅스 웹페이지는 지도상에 매장의 위치를 표시하기 위해서 Ajax로 데이터를 호출하는 방식을 사용하는데 이것의 방식을 알아내서 어떻게 데이터를 가져와야 하는지도 알고 있어야 합니다.

보통 크롬이나 파이어폭스의 개발자도구를 사용해서 알아내는데 연습과 방법을 익히는데 시간과 노력이 필요합니다. IT활용능력, 웹개발능력과 관련이 있는 것이라서 이것까지 설명하려면 설명이 길어지므로 이것을 알아내는 방법은 여기서는 생략합니다. 다음 기회에 다른 포스트에서 하겠습니다.

이 글에 소스코드를 넣어 두었으니 이미 완성된 코드를 참고 참고하세요.

인구데이터는 국가통계포털 웹사이트에서 가져오면 됩니다. csv나 excel로 다운로드 할 수 있게 지원하므로 매우 편합니다만 그래도 역시 데이터 정제, 정돈 작업은 좀 필요합니다.

인구데이터는 여기 말고도 받을 수 있는 곳이 더 있습니다. 더 편한곳이 있으면 그냥 거기를 이용하세요.

데이터를 크롤하는 법

R언어는 텍스트 파일을 파싱하거나 json 데이터를 처리하는 것이 조금 복잡한 편에 속합니다. R언어가 수치와 벡터 계산에 중점을 두기 때문에 이런 텍스트 처리에는 매우 약합니다.

하기가 까다롭다는 말입니다.

이런 것을 하려면 Python이나 Javascript가 더 나은 선택이지만

R언어로 이걸 하면 한 코드에서 데이터 크롤, 정제, 분석, 시각화까지 한 번에 할 수 있어 관리가 편하고 나중에 코드를 다시 볼 때 전체 흐름을 이해하기 편하다는 장점이 있습니다.

어쨌든 R언어에서 httr, urltools, jsonlite 패키지의 사용법을 익히면 됩니다.

데이터 정제, 정돈

데이터랭글링이라는 것을 할 텐데 이런 작업은 tidyverse 패키지에 포함된 여러 패키지를 이용하는 것이 가장 세련되고 좋은 방법입니다.

그리고 시각화는 ggplot2를 사용하겠습니다.

결과

스타벅스 전체 매장수: 1658개

1658개로 나옵니다. 스타벅스는 모두 신세계에서 운영하는 직영점이라고 알려져 있고 관리가 웹사이트 관리가 잘 되고 있을 것이라고 생각돼서 이 수치는 맞을 것입니다.

수천개는 될 것 같지만 제 예상보다는 적습니다.

시도별 매장수

   sido               n
   <chr>          <int>
 1 서울특별시       571
 2 경기도           383
 3 부산광역시       128
 4 대구광역시        71
 5 인천광역시        67
 6 경상남도          66
 7 광주광역시        59
 8 대전광역시        59
 9 경상북도          48
10 충청남도          36
11 울산광역시        29
12 전라북도          29
13 강원도            28
14 충청북도          26
15 전라남도          25
16 제주특별자치도    22
17 세종특별자치시    11

시도별 매장수는 역시 서울이 가장 많고 그 다음은 경기도, 부산 순입니다. 인구수가 많은 시도에 매장이 더 많은 것을 알 수 있습니다.

네 당연하죠. 물론 지역별로 로컬 카페나 다른 프렌차이즈, 브랜드의 커피매장이 더 인기가 있는 지역이 있을 수도 있으니 이 가설이 틀렸을 여지는 있습니다.

차트로 보며 시도별 매장수의 규모를 더 직관적으로 확인할 수 있는데 서울특별시와 경기도를 합치면 다른 시도를 다 합친 것 보다 더 많습니다.

우리나라 스타벅스 매장은 수도권에 크게 집중되어 있습니다.

구군별 매장수

   sido       gugun        n sido_gugun           
   <chr>      <chr>    <int> <chr>                
 1 서울특별시 강남구      88 서울특별시   강남구  
 2 서울특별시 중구        52 서울특별시   중구    
 3 서울특별시 서초구      48 서울특별시   서초구  
 4 경기도     성남시      47 경기도   성남시      
 5 경기도     고양시      42 경기도   고양시      
 6 서울특별시 영등포구    40 서울특별시   영등포구
 7 서울특별시 종로구      39 서울특별시   종로구  
 8 경기도     수원시      35 경기도   수원시      
 9 경기도     용인시      34 경기도   용인시      
10 서울특별시 송파구      34 서울특별시   송파구  

구군별로 매장수를 살펴보면 역시 서울 강남구가 가장 많습니다. 한국에서 아마 인구밀도가 가장 높은 지역이며 유동인구와 일과시간에 직장인이 가장 많이 있는 곳입니다.

그 다음은 역시 유동인구가 가장 많고 오피스밀집 지역이며 인구밀도가 높은 서울 중구입니다. 중구에는 명동, 충무로, 을지로가 있습니다.

그 다음은 서울 서초구인데 서초구는 강남구와 인구밀도는 비슷하지만 오피스공간 보다는 주거지역이 훨씬 많기 때문에 강남구나 중구에 비해서 낮시간에 직장인이 아주 많지는 않습니다. 그래도 괘나 많습니다.

그리고 그 다음은 경기도 성남시인데 성남에는 분당과 판교가 있으며 성남전체의 인구도 많으므로 이것도 당연합니다.

서울-강남구에 스타벅스가 압도적으로 많으며 다른 대형 지역구들도 제법 많습니다. 앞서 말했듯이 이 지역은 직장인들이 주중에 많이 머무는 지역들입니다. 물론 여기 나온 인구수는 거주 인구수이기 때문에 직장인이 주중에 많다는 것과의 상관관계를 다시 확인해야 할 필요가 있습니다만 알려진 바로는 매우 특별한 경우를 빼면 거주인구가 많은 지역에 직장도 많습니다.

인구수와 매장수의 상관관계

	Pearson's product-moment correlation
data:  sido_tbl$n and sido_tbl$total
t = 7.6707, df = 15, p-value = 1.439e-06
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7216524 0.9609928
sample estimates:
      cor 
0.8926678 

시도별 인구수와 스타벅스 매장수의 상관관계를 보면 상관계수가 0.89로 강한 상관이며 검정에서 대립가설 채택으로 상관이 있다는 결과가 나옵니다.

더 해볼 것

상관관계를 볼 때 단순 인구수가 아닌 면적을 인구수로 나눠서 인구밀집도를 구한 다음에 상관관계를 보는 것이 더 합리적이겠지만 면적데이터를 가져와서 붙여야 하니 귀찮아서 생략하겠습니다.

또 구군별로도 면적데이터를 가져와서 구군별로도 인구수와 스타벅스 매장수가 상관이 있는지 확인해 보는 것도 필요합니다만 이것도 생략하겠습니다.

혹시 해보고 싶으시면 아래 소스를 보시고 고쳐서 직접 한 번 해보세요.

결론 및 인사이트

매장수와 지역의 인구밀집도는 관계가 있습니다.

시도별, 구군별로 모두 상관관계가 있습니다.

따라서 스타벅스매장이 많은 곳은 인구밀집도가 높은 지역일 가능성이 큽니다.

인구밀집도는 유동인구수와 상관관계가 있는 것으로 알려져 있습니다.

스타벅스 매장이 많은 곳(있는 곳)은 유동인구가 많은 곳입니다.

마약 누군가 많은 유동인구가 필요한 점포를 개업하려고 한다면 스타벅스 부근에 개점하면 됩니다.

길거리 음식을 팔거나 판매하려면 패션 팟업스토어, 푸드 트럭을 열려면 스타벅스 근처에 하면 잘 될 것입니다. 물론 그게 가능하다면 말이죠.

전체 스크립트

소스 파일

https://github.com/euriion/r-exams/blob/main/starbucks_analysis.R

소스 내용

# 스타벅스 목록을 읽어서 간단한 통곗값을 출력하는 R 스크립트
# install.packages(c("httr", "urltools", "jsonlite"))
library(httr)
library(urltools)
library(jsonlite)
# 데이터를 긁어올 사이트: https://www.starbucks.co.kr
# 시도 목록을 가져오는 부분
url <- "https://www.starbucks.co.kr/store/getSidoList.do"
res_content <- POST(url)
res_object <- fromJSON(content(res_content, "text"))
sido_items <- tibble(sido_nm=res_object$list$sido_nm, sido_cd=res_object$list$sido_cd)
# 구군 목록을 가져오는 코드. 구군은 분석에 필요하지 않으므로 리마킹
# url = "https://www.starbucks.co.kr/store/getGugunList.do"
# post_params = "sido_cd=01&rndCod=4X93H0I94L"
# res_content <- POST(url, body=parse_url(sprintf("%s?%s", url, post_params))$query)
# res_object <- fromJSON(content(res_content, "text"))
# 각 시도별 주소를 가져오는 부분
url <- "https://www.starbucks.co.kr/store/getStore.do"
payload <- "in_biz_cds=0&in_scodes=0&search_text=&p_sido_cd=08&p_gugun_cd=&in_distance=0&in_biz_cd=&isError=true&searchType=C&set_date=&all_store=0&whcroad_yn=0&P90=0&new_bool=0&iend=1000"
post_params <- parse_url(sprintf("%s?%s", url, payload))$query
res_content <- POST(url, body = post_params)
res_object <- fromJSON(content(res_content, "text"))
# 시도 코드와 이르을 받아서 주소목록이 들어 있는 data.frame을 리턴하는 함수
get_addrs <- function(sido_cd, sido_nm) {
  url <- "https://www.starbucks.co.kr/store/getStore.do"
  payload <- sprintf("in_biz_cds=0&in_scodes=0&search_text=&p_sido_cd=%s&p_gugun_cd=&in_distance=0&in_biz_cd=&isError=true&searchType=C&set_date=&all_store=0&whcroad_yn=0&P90=0&new_bool=0&iend=10000", sido_cd)
  post_params <- parse_url(sprintf("%s?%s", url, payload))$query
  res_content <- POST(url, body = post_params)
  res_object <- fromJSON(content(res_content, "text"))
  cbind(rep(sido_cd, length(res_object$list$addr)), rep(sido_nm, length(res_object$list$addr)), res_object$list$addr)
}
# 데이터랭글링
# install.packags(c("tidyverse", "stringi"))
library(tibble)
library(dplyr, warn.conflicts = FALSE)
library(stringi)
df <- sido_items |> rowwise() |> mutate(addr=list(get_addrs(sido_cd, sido_nm)))
tbl <- do.call(rbind.data.frame, df$addr)
names(tbl) <- c("sido_cd", "sido_nm", "addr")
tbl <- tbl |> rowwise() |> mutate(addrsplit=stri_split_fixed(addr, " ", 4))
tbl <- as_tibble(do.call(rbind.data.frame, tbl$addrsplit))
names(tbl) <- c( "sido", "gugun", "dong", "bunji")
tbl |> count()  # 전체 매장 개수
stat_sido <- tbl |> count(sido) |> arrange(desc(n))  # 시도별 매장 수
stat_gugun <- tbl |> count(sido, gugun) |> arrange(desc(n)) |> mutate(sido_gugun=paste(sido, " ", gugun))  # 시도별 매장 수
# 시각화
library(ggplot2)
p <- ggplot(stat_sido, aes(x =reorder(sido, n), y = n)) +
  geom_col(aes(fill = n), width = 0.7)
p <- p + coord_flip()
p <- p + xlab('시/도')
p
p <- ggplot(head(stat_gugun, 20), aes(x =reorder(sido_gugun, n), y = n)) +
  geom_col(aes(fill = n), width = 0.7)
p <- p + coord_flip()
p <- p + xlab('구/군')
p
# 데이터 출처: # https://kosis.kr/statHtml/statHtml.do?orgId=101&tblId=DT_1B040A3&checkFlag=N
pop_sido_text_data <- "sido,total,male,female
서울특별시,9505926,4615631,4890295
부산광역시,3348874,1638207,1710667
대구광역시,2383858,1174667,1209191
인천광역시,2949150,1476663,1472487
광주광역시,1441636,713037,728599
대전광역시,1451272,724026,727246
울산광역시,1121100,575939,545161
세종특별자치시,374377,186907,187470
경기도,13571450,6830317,6741133
강원도,1538660,774315,764345
충청북도,1597097,810548,786549
충청남도,2118638,1083242,1035396
전라북도,1785392,888291,897101
전라남도,1832604,922190,910414
경상북도,2624310,1322509,1301801
경상남도,3311438,1666968,1644470
제주특별자치도,676691,339071,337620
"
pop_sido_tbl <- read.csv(textConnection(pop_sido_text_data))
sido_tbl <- pop_sido_tbl |> inner_join(stat_sido, by = "sido")
# 상관계수
cor(sido_tbl$n, sido_tbl$total)
# 결괏값: 0.8926678
cor.test(sido_tbl$n, sido_tbl$total)

여기까지 입니다.

git 에러 – fatal: refusing to merge unrelated histories

git pull을 하다 보면 다음과 같은 에러가 나올 때가 있습니다.

git pull
fatal: refusing to merge unrelated histories

이 에러는 로컬의 브랜치와 리모트의 브랜치를 서로 각각 init을 한 후에 pull이나 push할 때 생기는 에러입니다.

두 레파지토리에 서로 연관이 없는 히스토리가 들어 있다는 것인데

해결법은 히스토리 관계 검사를 무시하는 옵션을 추가해서 git pull을 하면 됩니다.

git pull origin main --allow-unrelated-histories

rsync 소스 디렉토리에 없는 파일을 목표 디렉토리에서 삭제하기

데이터를 처리하는 중에 moving windows와 같은 방식으로 데이터 파일을 관리하고 원격 서버에서 데이터를 보내거나 가져오는 일을 하는 경우가 많습니다. 여러가지 방법으로 이 작업을 할 수 있지만 가장 쉽고 편한 방법은 rsync를 사용하는 것입니다.

rsync의 기본 옵션은 소스 디렉토리에 파일이 없고 목표 디렉토리에 있는 경우에 목표 디렉토리의 파일을 삭제하지 않습니다. 안전을 위해서 기본값으로 설정하지 않은 것인데요.

하지만 여러가지 목적으로 소스 디렉토리에 파일이 삭제되면 목표 디렉토리에서 삭제해버리고 싶을때가 있습니다.

다음과 같이 –delete 옵션을 사용하면 됩니다.

rsync -avzrub --delete /data/source_files user01@server01.euriion.com:/data/dest_files/

하지만 다음과 같이 rsync를 사용할 때 소스 디렉토리에 파일을 지정하게 되면 작동하지 않으므로 주의해야 합니다.

rsync -avzrub --delete /data/source_files/* user01@server01.euriion.com:/data/dest_files/

python 파일의 생성날짜 출력하기

데이터 파일이 생성된 날짜 또는 수정된 날짜를 알아내서 화면이나 웹페이지에 표시해주고 싶은 경우가 있습니다.

Python에서 파일의 생성 날짜를 알아내려면 os.p0ath.getctime() 을 사용하면 됩니다.

하지만 os.path.getctime()은 1382189138.419602 와 같이 정수에 날짜를 소수에 시분초를 표기하는 형식을 사용합니다.

os.path.getctime()

getctime으로 받은 숫자를 우리가 흔히 보는 문자열 형태의 시간 표기법을 사용하면 다음과 같이 하면 됩니다.

from datetime import datetime
datetime.fromtimestamp(1382189138.4196026).strftime('%Y-%m-%d %H:%M:%S')

합쳐서 하면 다음과 같습니다.

datetime.datetime.fromtimestamp(os.path.getctime(model_path)).strftime('%Y-%m-%d %H:%M:%S')

추가로 파일의 수정날짜는 os.path.getmtime() 함수를 사용하면 됩니다.

쉘스크립트 시작 날짜 끝 날짜로 날짜 목록 만들기 / shell script – get date list with begin date and end date

bash shell script로 시작날짜와 끝날짜의 목록으로 날짜목록을 만드는 코드입니다.

여러 날짜에 대해서 일별로 일괄처리를 할 때 자주 쓰는 코드입니다.

#!/usr/bin/env bash

begin_date="20210101"
end_date="20210201"

date_delta_days=$(( ($(date --date="$end_date" +%s) - $(date --date="$begin_date" +%s) )/(60*60*24) ))
for (( i=0; i<=date_delta_days; i++ )); do
    date_str=$(date --date="$begin_date +$i days" +%Y%m%d)
    echo "$date_str"
done

결과

20210101
20210102
20210103
20210104
20210105
20210106
20210107
20210108
20210109
20210110
20210111
20210112
20210113
20210114
20210115
20210116
20210117
20210118
20210119
20210120
20210121
20210122
20210123
20210124
20210125
20210126
20210127
20210128
20210129
20210130
20210131
20210201

git 오류 fatal: unable to connect to cache daemon: Permission denied

git pull 또는 push를 할 때 다음과 같은 오류가 나오는 경우가 있습니다.

fatal: unable to connect to cache daemon: Permission denied

sudo를 사용하거나 권한을 잘못 변경하고 git를 사용하다가 발생한 문제인데 ~/.cach/git/credential 디렉토리의 권한을 현재 사용자에게 소유권을 다시 넘겨주면 해결됩니다.

다음과 같이 합니다.

sudo chown $(whoami) ~/.cache/git/credential/

Go언어 문자열에서 앞 또는 뒤 문자열 제거하기

Trim이라고 하는 그것입니다.

문자열에서 앞 또는 뒷쪽의 특정 문자열을 제거하는 코드입니다.

// Go program to illustrate 
// how to trim a string
package main
  
import (
    "fmt"
    "strings"
)
  
// Main method
func main() {
  
    // Creating and initializing string
    // Using shorthand declaration
    str1 := "!!Welcome to GeeksforGeeks !!"
    str2 := "@@This is the tutorial of Golang$$"
  
    // Displaying strings
    fmt.Println("Strings before trimming:")
    fmt.Println("String 1: ", str1)
    fmt.Println("String 2:", str2)
  
    // Trimming the given strings
    // Using Trim() function
    res1 := strings.Trim(str1, "!")
    res2 := strings.Trim(str2, "@$")
  
    // Displaying the results
    fmt.Println("\nStrings after trimming:")
    fmt.Println("Result 1: ", res1)
    fmt.Println("Result 2:", res2)
}

apt-get update failed because certificate verification failed because handshake failed on nodesource

apt install을 하는데 다음과 같은 에러가 나오는 경우가 있습니다.

apt-get update failed because certificate verification failed because handshake failed on nodesource

위 에러는 우분투 리눅스에 설치된 certification에 문제가 생겼기 때문입니다.

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

sudo apt install ca-certificates

우분투(Ubuntu)에 Neovim + Copilot 설치

우분투 리눅스(Ubuntu)를 터미널로 접속해서 Copilot을 사용하려면 Neovim을 사용해야 합니다.

귀찮게 설치하지 않고 Copilot을 안쓰면 되겠지만 Copilot을 사용하면 생산성이 너무 좋기 때문에 도저히 포기할 수 없습니다.

그래서 Neovim과 Copilt을 Ubuntu에 설치하려고 하면 간단하게 되지 안고 몇가지 문제가 생깁니다.

서버 마다 이걸 반복해서 하다보니 귀찮아서 설치법을 정리했습니다.

설치순서 요약

다음은 설치 순서요약입니다.

  • Node.js 12 이상 설치하기
  • Neovim 0.6 이상 설치하기
  • copilot.vim 설치하기
  • copilot.vim 활성화하기

우선 Copilot을 쓰려면 Github 계정이 있어야 하므로 계정을 먼저 준비하세요.

그 다음의 문제가 있는데 apt로 설치를 할 수 없는 것이 Node js 12와 Neovim 0.6입니다.

apt로 설치하면 Node.js와 Neovim이 상당히 낮은 구버전이 설치됩니다. 그래서 Copilot을 쓸 수 없습니다.

다음과 같이 하면 됩니다.

설치 방법

Node.js 12 설치

먼저 Node.js 12는 다음과 같이 설치합니다.

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install -y nodejs

Snap을 설치하고 Snap으로 Neovim 설치

Neovim를 설치하기 위해 snap을 설치합니다. apt로 설치하면 0.6 보다 낮은 구버전이 설치되는데 그 버전으로는 Copilot을 쓸 수 없습니다.

sudo apt install snap
snap install nvim --classic

Copilot Neovim 확장 설치

이제 Copilot 확장을 설치합니다. Github 레파지토리에서 그대로 클로닝을 해서 ~/.config 아래에 넣어주는 것이 전부입니다.

git clone https://github.com/github/copilot.vim.git ~/.config/nvim/pack/github/start/copilot.vim

Copilot 활성화

이제 Neovim을 실행해서 Copilot을 활성화해야 합니다.

Neovim에서 “:Copilot setup‘ 을 입력합니다.

원타임 인증 코드를 보여줍니다.

하이픈을 포함해서 9개의 글자를마우스로 드래그해서 복사하세요.

웹브라우저를 열고 https://github.com/login/device 주소를 입력해서 인증 페이지로 이동합니다.

인증페이지에서 위에서 복사한 코드를 그대로 붙여넣으세요.

문제가 없다면 인증이 완료됩니다.

Neovim으로 돌아오면 인증이 완료된 것을 볼 수 있습니다.

Copilot이 작동하는것을 볼 수 있습니다.

이제 터미널에서도 Copilot를 쓰면서 편하게 작업할 수 있겠습니다.

JetBrains IDE에서 오류메세지 보는 단축키

젯브레인 툴(JetBrains IDE)에서 소스 코드에 빨간 밑줄이 쳐지면 오류가 있다는 표시입니다.

빨간 줄 위에 마우스를 올리고 조금 기다리면 툴팁(풍선 처럼 뜨는 작은 팝업)으로 오류 메세지를 보여줍니다.

오류를 쉽게 인지하고 수정할 수 있게 해주기 때문에 상당히 유용한 기능입니다.

이걸 Error Description Tooltip 이라고 부르는데

그런데 마우스 올리고 시간이 조금 지나야 보이기 때문에 빨리 보려면 기다리는 시간이 답답할 때가 있습니다.

화면 예시

Error Description shortcut

단축키를 기억하고 있으면 툴팁을 바로 나오게 할 수 있습니다.

Error Description 툴팁을 바로 나오게 하는 단축키 입니다.

  • 윈도우 Windows: CTRL + F1
  • 맥 Mac: CMD + F1

MeCab 메카브 형태소 분석기

은전한닢 메카브 형태소 분석기

MeCab 형태소분석기에 대해서 간단히 설명하려고 합니다.

MeCab은 이제 우리나라에서 상당히 유명한 형태소 분석기가 되었지만 Mecab(메카부)는 일본어 형태소 분석기입니다.

영어로는 “미캡”이라고 읽어야 하는 것이 맞겠지만 원래 프로젝트 페이지에 카타가나 일본어 표기로 “메카부”라고 되어 있고 일본인들도 대부분 메카부라고 읽기 때문에 “메카부”라고 읽는 것이 맞습니다. 사실 이건 그리 중요하지는 않습니다.

어쨌든 이 포스트에서도 메카부로 읽고 쓰겠습니다.

원래 NTT(일본 통신)에서 배포하는 오픈소스 일본어 형태소분석기이고 제작자는 구글로 이직한 것으로 알려져 있습니다.

상당히 좋은 성능으로 오랫동안 일본에서 가장 많이 쓰이는 오픈소스 형태소분석기 중 하나였습니다.

한국에는 변변한 오픈소스 형태소분석기가 없었던 시절 일본어와 문법체계가 비슷한 한국어를 위해 Mecab를 한국어 용으로 포팅한 은전한닢이라는 프로젝트가 생겨 Mecab를 한국어 용으로 사용하면서 한글 및 한국어 자연어처리 발전에 상당히 기여했습니다.

원본 Mecab를 한국어에서 사용할 수 있는가?

없습니다. 일본어는 한국어와 다르고 일본어에는 필요 없는 것과 한국어에만 있는 것을 적용하는 작업이 필요한데 그 작업을 해 놓은 것이 은전한닢입니다.

은전한닢의 학습 데이터는 어떤 것을 사용했는가?

세종계획 말뭉치와 다른 소스를 사용하고 있다고 알려져 있고 세종계획말뭉치로 학습을 해서 사용해보면 거의 같습니다.

메카부의 구성

메카부는 C++로 작성했습니다. C++만든 모듈은 대부분의 언어에 바인딩을 할 수 있기 때문에 대부분의 언어에서 지원이 가능합니다.

C++, Java, Python, R 등이고 모두 패키지가 있습니다. 물론 안되는 것도 많습니다.

기타 자료

현재는 여러곳에서 파생된 패키지와 소스를 받을 수 있습니다.

Mecab 위키피디아 설명

https://en.wikipedia.org/wiki/MeCab

Mecab 일본어 웹버전

https://fasiha.github.io/mecab-emscripten/

https://github.com/fasiha/mecab-emscripten#mecab-on-the-web

은전한닢 프로젝트 페이지

https://eunjeon.blogspot.com/

Go언어 cron 처럼 스케줄링 하기

cron과 같은 유형의 스케줄러는 데이터 처리를 할 때 반드시 필요합니다.

데이터과학자들은 주로 젠킨스(Jenkins)나 airflow를 사용하겠지만 Python이나 Go로 직접 작성해야 하는 경우도 종종 생깁니다.

패키지 “github.com/jasonlvhit/gocron” 를 사용하는 방법입니다.

package main

import (
	"fmt"
	"github.com/jasonlvhit/gocron"
	"time"
)

func task() {
	fmt.Println("태스크를 실행합니다.")
}

func taskWithParams(a int, b string) {
	fmt.Println(a, b)
}

func main() {
	// 파라미터 없이 잡을 실행
	gocron.Every(2).Seconds().Do(task)
	gocron.Every(1).Minute().Do(task)
	gocron.Every(2).Minutes().Do(task)
	gocron.Every(1).Hour().Do(task)
	gocron.Every(2).Hours().Do(task)
	gocron.Every(1).Day().Do(task)
	gocron.Every(2).Days().Do(task)
	gocron.Every(1).Week().Do(task)
	gocron.Every(2).Weeks().Do(task)

	// 파라미터를 지정해서 잡을 실행
	gocron.Every(1).Second().Do(taskWithParams, 1, "hello")

	// 지정한 요일에 잡을 실행
	gocron.Every(1).Monday().Do(task)
	gocron.Every(1).Thursday().Do(task)

	// 지정한 시각에 잡을 실행 - 'hour:min:sec' - seconds optional
	gocron.Every(1).Day().At("10:30").Do(task)
	gocron.Every(1).Monday().At("18:30").Do(task)
	gocron.Every(1).Tuesday().At("18:30:59").Do(task)

	// Begin job immediately upon start
	gocron.Every(1).Hour().From(gocron.NextTick()).Do(task)

	// Begin job at a specific date/time
	t := time.Date(2019, time.November, 10, 15, 0, 0, 0, time.Local)
	gocron.Every(1).Hour().From(&t).Do(task)

	// NextRun은 다음번 실행될 시간을 알려줌
	_, time := gocron.NextRun()
	fmt.Println(time)

	// 지정한 태스크 제거
	gocron.Remove(task)

	// 모든 스케줄 작업을 제거
	gocron.Clear()

	// 모든 펜딩잡을 시작
	<-gocron.Start()

	// 새 스케줄러를 생성해서 동시에 2개의 스케줄러를 실행
	s := gocron.NewScheduler()
	s.Every(3).Seconds().Do(task)
	<-s.Start()
}

sudo에서 http_proxy 환경변수 적용받기su

일반 계정에서 http_proxy 환경변수를 설정해서 작업을 하다가 sudo를 사용해서 root 권한을 사용할 때 http_proxy 설정이 적용되지 않아 힘들때가 있습니다.

sudo visudo를 하거나 sudo vim /etc/sudoers을 해서 sudoers 파일에 다음의 줄을 추가해 주면 됩니다.

http_proxy 뿐만 아니라 다른 환경변수도 동일한 방법으로 넘겨주는 것이 가능합니다.

Defaults  env_keep +="http_proxy"
Defaults  env_keep +="https_proxy"
Defaults  env_keep +="HTTP_PROXY"
Defaults  env_keep +="HTTPS_PROXY"

혼동행렬 Confusion Matrix

기계학습 모델 평가지표

기계학습으로 생성한 분류 모델, 예측 모델에서 빠지지 않고 나오는 혼동 행렬 (confusion matrix) 입니다.

이름이 혼동행렬(Confusion matrix)인 이유?

기계가 얼마나 참과 거짓을 혼동하는지 확인하는데 사용하는 표이기 때문입니다.

간단하죠.

5개의 주요 성능 지표

혼동행렬에서는 특이도, 정확도, 민감도, 정밀도, 재현율 다섯개의 값은 외워야 합니다.

이중에서 가장 많이 쓰는 것은 정밀도(precision)재현율(recall)입니다.

기계학습 모델의 성능을 한 지표로만 설명하라고 할 때 쓰는 것은 정확도(Accuracy)와 혼동행렬에는 없지만 F1-measure (F1 값)이 있습니다.

F1값은 정밀도화 재현율의 조화평균입니다.

AUROC와 Precision-Recall 그래프

여기서 특이도와 민감도는 ROC 및 AUC 를 계산할 때 쓰고

정밀도와 재현율은 AP 와 Precision-Recall 그래프를 계산할 때 씁니다.

혼동행렬 confusion matrix

아래는 혼동행렬(Confusion Matrix)입니다. 표가 좀 안 이쁘지만 힘들게 그렸으니 알아서 잘 봐주세요.

예측값 Forecast
참 TRUE거짓 FALSE
실제값 Actual참 TRUETP (True Positive)FN (False Negative)
거짓 FALSE FP (False Positive)TN (True Negative)

지표 설명 및 계산법

각 지표값의 정의적 설명과 계산법입니다.

민감도 (Sensitivity)(TP / (TP + FN)) 양성 중 맞춘 양성의 수
특이도 (Specificity)(TN / (FP + TN)) 음성 중 맞춘 음성의 수
정밀도 (Precision)(TP / (TP + FP)) 양성이라고 판정 한 것 중에 실제 양성 수
재현율 (Recall)(TP / (TP + FN)) 전체 양성 수에서 검출 양성 수
정확도 (accuracy)((TP + TN) / (TP + FN + FP + TN)) 전체 개수 중에서 양성과 음성을 맞춘 수

풀어쓴 설명

민감도: 기계가 양성. 즉, positive를 얼마나 잘 꺼내서 맞췄는가를 봅니다.

특이도: 기계가 음성. 즉, Negative인 것을 양성이 아니라고 했는지를 봅니다.

민감도와 특이도는 보통 질병이나 의료에서 많이 쓰는 평가 지표입니다.

정밀도: 기계가 참이라고 했는데 실제 참인 것의 비율입니다. 기계가 얼마나 참을 순도 높게 찍어 내는지 보는 것입니다. 많이 맞추고 아니고는 별로 의미가 없이 기계가 참이라고 한 것 중에 참을 본 것이기 때문에 민감도와 헷갈리면 안됩니다.

재현율: 전체의 실제 참들 중에서 얼마나 기계가 참이라고 골라낸 비율입니다.

정확도: 전체 개수 중에서 기계가 실제 참을 참이라고 하고 실제 거짓을 거짓이라고 한 비율입니다.

습득 요령

처음에 보면 무척 헷갈리는데 외우는 것 보다는 이름과 계산법을 잘 기억하고 의미와 용도를 기억하는 것이 좋습니다. 기억이 안나면 그때 그때 찾아봐도 되지만 매우 빈번하게 쓰이는 것이므로 데이터과학을 공부한다면 그냥 암기해버리는 것이 효율적입니다.

Go언어 csv.gz 한줄씩 읽어오기

Go언어로 CSV파일을 한줄씩 읽어오는 방법입니다.

파일을 메모리에 올려서 한 번에 처리하면 파일이 큰 경우에는 메모리를 다 쓰기 때문에 스왑을 사용해서 문제를 만듭니다.

조금 느리더라도 파일은 1줄씩 읽거나 조금씩 읽어야 합니다.

// csv.gz 파일에서 데이터를 한 줄씩 읽어오는 방법
package main

import (
	"compress/gzip"
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	file, err := os.Open("product_titles.csv.gz")

	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	gzipReader, err := gzip.NewReader(file)

	if err != nil {
		log.Fatal(err)
	}

	defer gzipReader.Close()

	csvReader := csv.NewReader(gzipReader)
	csvReader.Comma = '\t'
	csvReader.FieldsPerRecord = -1

	for {
		record, err := csvReader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}

		// 첫번째 필드만 꺼내오기
		fmt.Println("record count:", len(record))
		if len(record) < 1 {
			log.Println("record is empty")
			continue
		}
		field1 := strings.Trim(record[0], " ")
		if len(field1) < 1 {
			log.Println("field1 is empty")
			continue
		}

		fmt.Println("field1:", field1)
	}
}

Nvidia의 각종 AI 데모 사이트 – Nvidia AI demo site

Nvidia의 AI 데모를 볼 수 있는 사이트입니다.

굉장히 재밌는 것들이 많습니다.

사이트주소: https://www.nvidia.com/en-us/research/ai-demos/

NVIDIA GAUGAN2

텍스트를 입력받아서 사진을 생성해줍니다.

단순한 그래픽이 아닌 실사와 다름없는 사실상 실사인 사진를 생성해줍니다.

NVIDIA AI Playground GAUGAN2

LYRICSTUDIO

노래의 가사를 만들어줍니다.

몇개의 단어와 노래를 입력받아 쓸만한 가사를 만들어줍니다.

LyricStudio

NVIDIA VID2VID CAMEO

2D사진을 넣으면 3D 동영상으로 가상의 아바타를 만들어줍니다.

NVIDIA Vid2Vid Cameo

NVIDIA IMAGE INPAINTING

이미지를 강화합니다. 이미지에서 피사체 중 하나를 지우거나 배경을 지울 수 있습니다.

이미지 강화는 여러 용도로 이용할 수 있습니다. 특히 상업용으로 사진을 사용하기 위해서 사진에서 상표나 인물 보기 싫은 대상체를 제거할 수 있습니다.

Image Inpainting

NVIDIA GANIMAL

애완동물의 표정을 다른 동물에게 입힙니다.

재미삼아 만든 것으로 보입니다만 어떤 용도로 쓸 수 있을지 고민을 해봐야 겠습니다.

NVIDIA AI Playground Ganimal

NVIDIA GAMEGAN

스스로 게임하는 인공지능을 만듭니다.

강화학습이라고 부르는 이 인공지능으로 유명한 것은 알파고가 있습니다.

NVIDIA AI Playground GameGAN

Go언어 csv.gz 파일 만들기 – Go writing of csv.gz file

Go언어로 csv.gz 파일을 만드는 코드입니다.

csv는 단순한 텍스트 파일이기 때문에 공간 절약을 위해서 요즘은 데이터 플랫폼들이 csv를 gzip으로 압축한 것을 바로 처리할 수 있도록 지원합니다.

그래서 파일을 만들때 단순한 csv를 만들지 않고 csv를 gzip으로 압축하는 것이 더 유리합니다.

// An example of writing to a csv.gzip compressed file.
package main

import (
	"compress/gzip"
	"encoding/csv"
	"fmt"
	"log"
	"os"
)

func main() {

	csvGzipFile, err := os.Create("output.csv.gz")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer csvGzipFile.Close()

	gzipWriter := gzip.NewWriter(csvGzipFile)
	if err != nil {
		log.Fatal(err)
	}
	defer gzipWriter.Close()

	csvFileWriter := csv.NewWriter(gzipWriter)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer csvFileWriter.Flush()

	records := [][]string{{"item1", "value1"}, {"item2", "value2"}, {"item3", "value3"}}
	for _, record := range records {
		err := csvFileWriter.Write(record)
		if err != nil {
			fmt.Println("Error:", err)
			return
		}
	}
}

Go언어 CSV 파일 쓰기 – Golang writing a csv file

Go언어로 CSV 파일을 만드는 코드입니다.

데이터 과학 업무를 하다보면 데이터처리를 할 때 CSV 파일을 빈번하게 읽거나 만드는 일이 있습니다.

특히 사이즈가 큰 파일은 처리 속도도 매우 중요하기 때문에 Go나 Rust, C++로 처리해야 할 수 있습니다.

Go언어로 CSV 파일을 처리하는 방법을 알아 두면 그럴 때 편하게 쓸 수 있습니다.

package main

import (
	"encoding/csv"
	"fmt"
	"os"
)

func main() {
	csvFile, err := os.Create("output.csv")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer csvFile.Close()

	records := [][]string{{"item1", "value1"}, {"item2", "value2"}, {"item3", "value3"}}

	writer := csv.NewWriter(csvFile)
	for _, record := range records {
		err := writer.Write(record)
		if err != nil {
			fmt.Println("Error:", err)
			return
		}
	}
	writer.Flush()
}

When you work on data science. you frequently deal with CSV files. and sometimes the CSV files are so big. in that case, processing speed is also important.

So you need to know how can you deal with CSV files with high-performance computer languages like Go, Rust, C++.

Go언어 FastText 모델 로딩해서 예측 수행하기 – Golang do prediction with built model

Facebook FastText로 만든 분류모델 (supervised model)을 로딩해서 prediction하는 간단한 코드입니다.

FastText 모델은 Python으로도 로딩해서 사용할 수 있습니다.

하지만 Python은 멀티쓰레드를 사용하기가 어려우니 빠른 속도를 위해서 Go언어나 다른 언어를 써야 할 때가 있으니 알아두면 좋습니다.

// FastText prediction
package main

import (
	"fmt"
	fasttext "github.com/bountylabs/go-fasttext"
)

func main() {
	model := fasttext.Open("//model/fasttext01.bin")
	fmt.Println("Prediction...")
	predictResult, err := model.Predict("분류할 입력 텍스트입니다.")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("Label: %s, Prob: %fs\n", predictResult[0].Label, predictResult[0].Probability)
}

FastText provide a command-line process to make a model. to apply the model to production, you may want write code for processing particular logic.

so, you need to know how cat load prebuilt FastText model and process prediction with Go language

Go언어 명령행 인수 처리 – Golang getting arguments from command line

Go언어에서 명령행 인수를 처리하는 방법입니다.

몇가지 방법이 더 있지만 여기에서는 flag 모듈를 사용합니다.

package main

import (
	"flag"
	"fmt"
)

func main() {
	file := flag.String("file", "default.txt", "Input file")
	maxcpu := flag.Int("maxcpu", 10, "Max CPU Count")
	isForce := flag.Bool("force", false, "Run force")

	flag.Parse()

	// 포인터 변수이므로 앞에 * 를 붙어 deference 해줘야 한다.
	fmt.Printf("file: %s\n", *file)
	fmt.Printf("maxcpu: %d\n", *maxcpu)
	fmt.Printf("force: %t\n", *isForce)
}

/* 테스트
C> go build exam_arguments.go
C> exam_arguments -file=test.csv -maxtrial=5 -force=true
*/

Go언어 CPU 수 알아내기

Go언어에서 CPU 수를 알아내는 코드입니다.

// OS, 아키텍쳐, CPU수, 고루틴 수를 출력한다.
package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Println("OS\t\t", runtime.GOOS)
	fmt.Println("ARCH\t\t", runtime.GOARCH)
	fmt.Println("CPU\t\t", runtime.NumCPU())
	fmt.Println("Goroutines\t", runtime.NumGoroutine())
}

Go언어 파일 목록 읽기

특정 디렉토리에 있는 파일 목록을 읽어오는 코드입니다.

요점

ioutil.ReadDir 함수를 사용하면 됩니다.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

func main() {
	files, err := ioutil.ReadDir("/tmp/")
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		fmt.Println(file.Name(), file.IsDir())
	}
}

How to retrieve a list of files from a particular directory.

Use “iotuil.ReadDir”

Go언어 csv.gz 읽기

csv파일은 gzip 압축이 되는 경우가 많습니다.

압축을 따로 풀지않고 gz 압축된 csv 파일을 직접 처리하는 것이 더 편할때가 많아졌습니다.

Go언어에서 gzip으로 압축된 csv 파일을 읽는 방법입니다.

package main

import (
	"compress/gzip"
	"encoding/csv"
	"fmt"
	"log"
	"os"
)

func main() {
	file, err := os.Open("data.csv.gz")

	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	gzipReader, err := gzip.NewReader(file)

	if err != nil {
		log.Fatal(err)
	}

	defer gzipReader.Close()

	csvReader := csv.NewReader(gzipReader)
	record, err := csvReader.Read()

	if err != nil {
		log.Fatal(err)
	}

	for _, v := range record {
		fmt.Println(v)
	}
}

윈도우에서 Go언어 개발할 때 Avast 경고메세지 없애기

윈도우에서 Go언어로 개발할 때 Avast를 백신으로 사용하고 있다면 잦은 실행파일을 빌드할 때 마다 검사 경고가뜹니다.

디버깅이나 실행버튼을 누를때마다 이런 일이 일어나기 때문에 굉장히 귀찮고 소리도 무척 거슬립니다.

해결책

Avast의 CyberCapture 기능을 비할성화하면 이 문제가 사라집니다.

주의점

물론 보안상 조금 더 위험해집니다.

작업이 끝나면 원래대로 설정을 바꿔 놓을 수 있습니다.

스크린샷

When developing a Golang application in Windows, how to disable the alert message.

If you develop an application with Golang in the environment which use Avast antivirus for Antivirus solution then you may frequently see alert message from Avast antivirus. for the purpose of removing the alert message.

Solution. You can disable the CyberCapture in your Avast configuration.

쉘스크립트 IF문 – shell script if elif else

쉘스크립트(shell script)로도 If elif 를 사용할 수 있습니다.

가끔 쓰기 때문에 기억이 잘 나지 않아서 말이지요.

그리고 case 구문을 지원하기 때문에 여러 조건을 확인해야 하는 것도 가능하지만

case문은 가독성이 너무 떨어지기 때문에 거의 사용하지 않습니다.

어쨌든 shell script (bash 기준)에서 if, elif, else 구문은 이렇게 씁니다.

#!/bin/bash

a="1"
if [[ $a == "1" ]]; then
    echo "a is 1"
elif [[ $a == "2" ]]; then
    echo "a is 2"
elif [[ $a == "3" ]]; then
    echo "a is 3"
elif [[ $a == "4" ]]; then
    echo "a is 4"
else
    echo "a is not 1, 2, 3, or 4"
fi

쉘스크립트 7일전 날짜 가져오기 – Shell script get date of 7 days ago

쉘스크립트에서 7일전 (1주일전) 날짜를 가져오는 방법입니다.

별로 어렵지 않은데 막상 쓰려면 기억이 잘나지 않죠.

아래와 같이 하면 됩니다.

date -d "7 days ago" +"%Y-%m-%d"

7일전부터 어제까지 7일간의 구간을 계산하려면 아래와 같이 하면 됩니다.

yesterday=$(date -d "1 days ago" +"%Y-%m-%d")  # 어제 날짜
ago7days=$(date -d "7 days ago" +"%Y-%m-%d")  # 7일전
echo "yesterday:$yesterday, ago7days:$ago7days"

cURL curl: (77) error setting certificate verify locations 에러

리눅스 curl 코맨드로 https url을 당겨올 때 에러가 날때가 있습니다.

curl: (77) error setting certificate verify locations:
  CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none

원인은 /etc/pki/tls/certs/ca-bundle.crt 가 없기 때문입니다.

다음과 같이 하면 처리됩니다.

sudo mkdir -p /etc/pki/tls/certs
sudo cp /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt

R언어 “Happy New Year 2022″를 출력하는 재밌는 코드

“Happy New Year 2022″를 출력하는 재밌는 코드입니다.

코드를 실행해 보세요.

seeds <- c(2219868, 10641, 443238, 9487)
word_lengths <- c(5, 3, 4, 4)
choices <- list(letters, letters, letters, 0:9)

magic_message <- function(seed, word_length, choices) {
  set.seed(seed)
  sample(choices, size = word_length, replace = TRUE) |>
    paste(collapse = "") |>
    stringr::str_to_title()
}

purrr::pmap_chr(list(seeds, word_lengths, choices), magic_message) |> cat()

버킷테스트 Bucket test

버킷테스트는 인터넷 사이트나 앱에서 흔히 하는 환경을 분리한 사용자 군을 대상으로 한 실험을 말합니다.

버킷테스트는 A/B테스트와 밀접한 관계가 있고 동일한 용어로 취급하기도 합니다.

그러니 A/B테스트에 대해서 잘 모른다면

예전에 A/B 테스트에 대해서 포스팅한 것이 있으니 먼저 참고하시기 바랍니다.

A/B 테스트 포스팅 글 👈

버킷테스트 개념

두 개의 양동이에 실험할 대상을 따로 떠내서 실험을 다르게 하던 것에서 출발한 것입니다.

버킷 = Bucket = 양동이

왜 버킷테스트라고 부르나?

버킷테스트는 사실상 A/B테스트와 거우 동일한데 A/B 테스트라고 하지 않고 버킷테스트라고 하는 이유가 있습니다.

A/B테스트는 원래 실험환경을 갖추고 통제된 환경에서 실험을 시작하지만 버킷테스트는 통제되지 않은 상황의 군집에서 일부를 꺼내서 실험을 하기 때문에 버킷테스트라고 부릅니다.

어떻게 하나?

예를 들어 설명해 보겠습니다.

먼저 실험설계를 합니다.

실험설계

유명한 포털사 네이박은 자신들이 운용하는 포털페이지의 기본 글꼴을 “맑은 고딕”에서 “탁한 고딕”으로 바꾸려고합니다. 이유는 “탁한 고딕”이 가독성이 더 높고 편안해서 사용자들이 글을 더 빨리 이해하고 클릭도 많이 할 것이라는 의견이 나왔기 때문입니다.

버킷테스트 진행

  1. 포털에 접속하는 사용자에게 발행한 쿠키를 기준으로 A그룹과 B구그룹으로 완전하게 분리할 수 있는 두 그룹을 만듭니다. 실험을 하는 동안 A그룹과 B그룹의 멤버들이 변화가 있어서는 안됩니다.
  2. A그룹은 전체 사용자의 1% B그룹은 전체 사용자의 1% 동일하게 하고 나머지 98%의 사용자는 내버려둡니다.
  3. 1%라는 수치는 포털의 전체 사용자수에 따라 달라지며 검정력 테스트라는 방법으로 필요한 샘플수를 알아낼 수 있습니다.
  4. A그룹은 내버려두고 B그룹이 보는 페이지에만 “맑은 고딕” 대신에 “탁한 고딕”을 적용합니다.
  5. 실험을 3주정도 진행합니다.
  6. 실험기간 동안 두 그룹의 클릭한 수, 페이지당 체류시간, 페이지 뷰 수 등 필요한 수치를 모두 뽑아냅니다.
  7. 가설검정을 통계적인 검정법으로 테스트합니다.
  8. B그룹의 클릭수 또는 클릭율이 더 높다면 대립가설 채택합니다.
  9. 전체 사용자를 대상으로 사이트의 폰트를 “탁한 고딕”으로 바꿉니다.

실험이 끝난 후에는 통계적 평가를 그대로 따르면 됩니다.

여기에서 가장 중요것은 A와 B그룹이 동일한 숫자여야 하고 서로 섞이지 않아야 하며 완전히 통제되야 한다는 것입니다.

A/B 테스트

A/B 테스트의 대해서 포스팅합니다.

무척 많이 쓰는 용어지만 잘 모르는 분들이 많습니다.

특히 A/B 테스트는 어설프게 알면 크게 당하기 쉽습니다. 만만해 보여도 개념을 잘못 잡으면 큰 착각을 하게됩니다.

개념

A/B 테스트는 A와 B가 유의미한 차이가 있는지 검정한다는 뜻입니다.

통계학에서 다루는 개념이며 실험입니다.

A와 B의 의미는 대조군을 A, 실험군을 B라고 의미없이 붙이는 것에서 나온 것입니다.

대조군은 원래 상태에 있는 것을 말하고

실험군은 원래 상타에서 뭔가를 바꾼 것을 말합니다.

알기 쉬운 예

콩발의 첨가물 테스트라는 아날로그식 예를 들어보겠습니다.

이 예제 테스트의 목적은

콩밭에 새로운 첨가물을 주고 이 첨가물이 전에 쓰던것 보다 더 콩의 수확량을 늘리는지 확인하려고 합니다.

다음과 같이합니다.

  1. 콩밭 1000제곱비터가 2개 있고 하나를 A 하나를 B라고 이름 붙입니다.
  2. A와 B에 동일한 종자의 콩을 심습니다. 다른 것 심으면 실험은 망합니다.
  3. A에는 원래 쓰던 첨가물을 쓰고 B에는 새로 개발한 첨가물을 씁니다.
  4. 동일한 조건으로 콩을 키웁니다. 물도 똑같이 주고, 햇빛도 똑같이 쬐게하고, 땅도 동일하게 다져줍니다.
  5. 콩을 수확합니다.
  6. A와 B에서 각각의 콩들을 무작위로 동일한 양을 꺼내서 무개를 잽니다. 무작위로 꺼내는 것이 싫으면 가능하다면 다 꺼내서 재도 되지만 그렇게 하는 경우는 없습니다.
  7. A와 B의 콩무게가 유의미한 차이가 있는지 확인합니다. 이걸 가설검정이라고 합니다.
  8. B의 콩무게가 더 무겁다면 B에 사용한 비료를 다음에 씁니다.

통제된 상태라는 것의 의미

여기서 중요한 것은

A와 B 모두 통제된 상태여야 합니다. 이 뜻은 A와 B가 콩을 기르는 동안 한쪽은 티가 많이 오고 한쪽은 그늘이 져서 햋볕이 잘 들어오지 않거나 하는 불평등한 상황이 되면 안된다는 것이고 첨가물을 다르게 준 것 외에는 조건이 동등해야 하는 것을 말합니다.

A와 B의 개체수가 동일해야 함

A와 B의 콩줄기의 숫자가 동일해야 합니다. 하지만 그러기는 매우 어려우니 대충 콩밭의 사이즈라도 동일해야 합니다. 한쪽이 크거나 하면 그것으로 인해서 콩의 수확양이나 성장 조건이 달라질 수 있기 때문입니다.

콩밭의 사이즈는 통상 한쪽이 다른 한쪽의 2%가 넘지 않게 합니다.

실험이 끝나면 가설검정을 해야 함

사실 B 콩밭에 첨가물을 다른 것을 준 이유는 콩 수확량이 증가할 것이라는 기대 때문입니다.

통계학에서는 귀무가설과 대립가설이라는 것을 정의하고 그것으 실험의 결과를 판단합니다.

여기에서 귀무가설은 A의 콩무메가 B의 콩무게와 차이가 없다.

대립가설은 B의 콩무게가 A의 콩무게와 차이가 있다.

이렇게 합니다.

여기서 실험결과가 귀무가설에 맞는지 대립가설에 맞는지를 확인하는 것을 가설검정이라고 합니다.

가설검정 공식

가설검정을 확인할 때는 공식이 있습니다.

무작정 A와 B에서 무작위로 콩을 골라서 무개를 재서 한쪽이 더 많은지 똑같은지 비교 하는 것은 안됩니다.

그렇게 하면 대부분의 경우 미세하게나마 한쪽의 콩무게가 더 무겁습니다.

쓸모없는 실험입니다.

상식적으로 생각해도 그게 정말 오류가 많을 수 있다는 것을 알 수 있습니다.

그래서 통계적으로 그 차이가 유의미한지 아닌지를 보는 연구된 방법을 쓰는데 그 방법은 매우 다양하고 많습니다.

그래서 각 상황에 맞게 어떤 통계적 검정 방법을 사용해야 하는지와 지켜야 할 것을 알아야 하는데 그걸 공부하는 학문이 통계학입니다.

위의의 콩무게와 같은 것은 스튜던트의 T테스트라는 테스트 공식으로 확인합니다.

스튜던트의 T테스트는 한쪽 집단의 평균과 다른 한쪽의 평균이 유의미한 차이가 있는지 의미없는 차이만 있는지 확인하는 유명한 방법입니다.

스튜던트의 T테스트는 엄청나게 유명한 테스트 방법입니다.

공식은 검색해서 찾아 보면 잘 나오므로 복잡하게 여기에서 설명하지 않겠습니다.

엑셀, Python, R을 비롯한 많은 통계 소프트웨어에 이런 가설검정법은 대부분 내장되어 있습니다.

Froala HTML 에디터

웹페이지에서 사용하는 콘텐트 편집기로 TinyMCE라는 유명한 것이 있습니다.

워드프레스를 포함한 많은 웹상의 편집기들이 이 편집기를 씁니다.

https://www.tiny.cloud/

TinyMCE 대안으로 Froala 라는 것이 있어 소개합니다.

https://froala.com/

장점

가볍고 깔끔합니다.

여러 플랫폼에 연동이 됩니다.

단점

자료가 많지 않아 문제가 생겼을 때 해결책을 찾기 어렵습니다.

네이버 블로그 검색 C-rank

네이버 블로그는 많은 디지털마케터들의 마케팅 도구, 수단이 되어 왔습니다.

한국에서 가장 큰 검색 포털이 네이버이고 그 다음이 카카오의 다음검색이기 때문입니다.

블로그 글을 작성해서 조회수를 올리고 어떤 상품이나 제품을 한국사람에게 보여줘서 광고나 홍보의 목적으로 노출하려면 네이버에 블로그를 올려야 합니다.

올린 글을 사람들에게 잘 검색되서 보여지고 검색 결과의 상단부에 위치할 수 있게 관리하는 것을 SEO(Search Engine Optimization, 서치엔지최적화)라고 합니다.

그리고 이런 SEO에 가장 효과가 좋은 것은 사상실 스팸(SPAM) 기술입니다.

이런 스팸성 기술을 방어하기 위한 노력은 오래전에 시작되었습니다.

세계 최고의 검색회사인 구글의 검색 결과의 랭킹은 유명한 PageRank 알고리즘에서 출발했습니다.

거기에 비해 네이버는 너무 오랫동안 검색 기술에 투자를 하지 않았고 구글의 기술력과 규모가 급속도로 발전하는 사이에 그 격차가 너무나 멀어졌습니다.

그리고 전통적으로 검색에서 사용되었던 단순한 TF/IDF나 콘텐트 기반의 검색 링킹으로는 SEO를 잘 알고 경험도 많은 블로거, 마케터, 콘텐츠 관리자들을 상대하기 버거워졌습니다.

그래서 네이버는 C-rank 알고리즘을 만들어 블로그 검색에서 Creater의 신뢰도를 검색랭킹의 자질(feature)중 하나로 사용하게 됩니다.

사실 구글의 페이지랭크는 콘텐트의 영향력을 기반으로 랭킹을 계속 업데이트하기 때문에 생산자의 신뢰도가 약하게 나마 그 자체에 포함되어 있다고 볼 수 있습니다. 물론 지금은 그보다 훨씬 복잡하고 많은 자질과 알고리즘을 쓴다고 알려져 있어 저렇게 단순하지 않을 것입니다. 하지만 네이버는 그런것조차 되어 있지 않았다는 것입니다.

어쨌든 네이버의 블로그글은 C-rank를 사용하기 때문에 이제 단순히 인기 키워드가 사람들이 검색을 많이 할 것 같은 키워드로 상위에 위치하는 것은 이미 어렵게 되어 있고 꾸준히 콘텐트를 올리고 사람들의 조회수를 늘려서 작성자의 신뢰도 점수를 올리지 않으면 블로그 콘텐츠를 상위에 노출하는 것은 어렵다는 것입니다.

그래서 네이버의 블로그 마케팅을 하려면 C-rank 알고리즘을 이해해야 합니다.

네이버 C-rank에서 사용하는 자질

오래전의 내용이기 때문에 지금과 많이 다르겠지만 아래의 표에 있는 것이 네이버 C-rank에서 사용하는 항목들입니다.

아래의 자질들이 나타내는 것을 요약해보면 스팸성 글들은 하위에 위치하도록 하겠다는 의도가 보입니다.

어떤 플랫폼이나 서비스에서도 스팸은 서비스의 품질을 떨어뜨리는 것입니다. 하지만 무작정 필터링할 수도 없는 것이 문제입니다. 그래서 결국 스팸 콘텐츠는 랭킹을 떨어뜨려 하위에 보이게 하도록 하는 거이 가장 좋은 방법입니다.

네이버의 C-rank 자질을 보면 그런 의도가 보입니다.

네이버 C-rank 때문에 블로그 마케팅은 불가능한가?

많은 블로그 마케터들이 여전히 성과를 내고 있습니다. 바꿔 말하면 방법이 있으며 여전히 C-rank가 방어하지 못하는 구멍이 있다는 것입니다.

이 방법에 대해서는 나중에 포스팅을 해보겠습니다.

네이버 C-rank 블로그 글

https://m.blog.naver.com/naver_search/220774795442

고스트 Ghost CMS

CMS (Content Management System)는 콘텐츠를 관리하는 시스템입니다.

여기서 말하는 콘텐츠는 글을 뜻합니다. 몇장의 이미지와 동영상이 포함될 수도 있지만 내용물의 중심은 글입니다.

글의 형식은 산문입니다. 블로그가 될 수도 있고 보고서가 될 수도 있습니다.

보통은 블로그, 뉴스레터 형식입니다.

대표적인 CMS는 워드프레스가 있습니다. 워드프레스는 지구상에서 가장 많이 사용되는 CMS입니다.

하지만 워드프레스는 PHP에 MySQL로 구동되서 조금 무겁다고 느껴지고 개인이 셀프 설치를 하려면 서버 호스팅을 받아야 하는 기술 장벽과 비용 장벽이 있습니다. 유/무료 서비스를 사용할 수도 있지만 커스터마이징 해서 사용하기 어렵다는 단점을 가지게 됩니다.

Ghost는 Node.js와 MySQL을 사용하는데 최종 결과물을 정잭 콘텐츠로 생성해서 배포하는 것까지 지원합니다.

상당힌 깔끔하고 가볍습니다.

다만 워드프레스 만큼 기능이 다양하지 않고 복잡한 커스터마이징은 되지 않습니다.

하지만 현재 워드프레스를 추격하며 가장 핫하게 떠오르는 CMS툴입니다.

자기의 서버에 설치를 할 수도 있고 서비스에 가입해서 사용할 수도 있습니다.

고스트의 주소입니다.

https://ghost.org

그리고 유명한 콘텐츠 큐레이션, 뉴스레터 서비스인 퍼블리도 ghost를 사용하고 있다고 알려져 있습니다.

깔끔한 d3 기반 그래프 metrics-graphics

d3 기반이나 Javascript 그래프, 플롯 라이브러리들은 쓰기 편하고 예쁜것들이 많지만

기능이 너무 많고 무겁고 복잡한 것도 많습니다.

d3 기반의 간단하고 깔끔한 라이브러리가 있어서 소개합니다.

metrics-graphics입니다.

아래 스크린샷을 보면 느끼겠지만 간단하고 깔끔합니다.

간단한 것이 없어서 고민했다면 한 번 사용해보세요.

사이트

https://metricsgraphicsjs.org/

소스코드

https://github.com/metricsgraphics/metrics-graphics

C/C++ 빌드 속도를 줄이는 방법 Unity Build

데이터 프로세싱을 할 때 고속으로 파일을 읽어서 계산을 하거나 비정형 데이터를 처리할 때 Go lang, Rust, C/C++을 써야 할 때도 있습니다.

Python, R, Shell script 만으로는 해결이 안되는 것들이 있습니다.

데이터 작업을 할 때 컴파일러를 포함한 빌드 언어의 문제는 여러가지가 있지만 큰 문제는

  • 인터랙티브 모드로 실행이 되지 않아서
  • 복잡한 코드일 수록 빌드 시간이 너무 길어서

위의 두 가지입니다.

데이터 과학에서는 첫번째 문제가 더 큰 장벽이 됩니다만 가끔 계산속도가 빠른 코드로 집계를 하거나 기계학습, 수리적 계산을 해야 할 때는 속도만을 위해서 사용성을 포기하고 컴파일 랭귀지를 사용할 때가 있습니다.

어쨌든 C/C++을 사용할 때 빌드 시간이 길어서 생기는 문제를 해결하는 획기적이면서 간단한 방법을 알게되어 소개드립니다.

Unity Build라는 것입니다.

원리는 간단한데 소스 코드를 한 개의 파일로 만들어서 빌드하는 것입니다.

자세한 내용은 아래의 블로그에 잘 설명되어 있으니 참고해 보세요.

우분투 18.04 에서 Python3.6 제거하기 – Uninstall python3.6 from Ubuntu 18.04

우분투 18.04에서 Python3.6을 제거하는 방법입니다.

제거를 하고 싶은 이유는

우분투에 Python 새버전을 추가로 설치하다보면 구버전이 계속 남아서 패키지를 설치할때 혼동이 되거나 오류가 발생하기도 해서 꼭 구버전을 제거하고 싶을 때는 다은과 같이 합니다.

그런데 제대로 안되는 경우가 많아서 하지 않는 것이 좋습니다. 우분투가 기본 패키지 버전을 관리하거나 시스템을 관리하는데 파이썬을 설치하기 때문에 함부로 제거하면 이런 시스템에 문제가 발생합니다.

어쨌든 파이썬을 제거하려고 한다면 다음의 명령대로 하면 됩니다.

sudo add-apt-repository --remove ppa:fkrull/deadsnakes  # 레파지토리 제거. 선택사항
sudo apt-get update  # apt 업데이트
sudo apt-get remove --purge python3.6  # 패키지 퍼지

우분투 18.04에 R 설치하기 – Install R on Ubuntu 18.04

우분투 18.04에 R을 설치하는 방법입니다.

요점

  • apt로 설치하는 것입니다.
  • Ubuntu 20.04에 설치하는 방법과는 조금 다를 수 있습니다.
  • 시스테에 최소 1Gb 메모리가 필요합니다.

리눅스 필요 패키지 설치

필요한 리눅스 패키지를 먼저 설치합니다.

sudo apt install apt-transport-https software-properties-common

R패키지가 있는 CRAN 레파지토리를 등록하고 GPG 키도 등록

R패키지를 설치하려면 CRAN을 apt에 등록하고 gpg키도 등록해줘야 합니다.

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9
sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu bionic-cran35/'

R 설치

apt를 업데이트해주고 r-base를 설치하면 끝납니다.

sudo apt update
sudo apt install r-base

R버전 확인

다음의 명령어로 버전을 확인합니다.

R --version

최신버전인지 확인합니다.

R version 4.1.2 (2021-11-01) -- "Bird Hippie"
Copyright (C) 2021 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
https://www.gnu.org/licenses/.

젠킨스 포트 변경 – Changing Jenkins HTTP port

젠킨스(Jenkins)의 웹서비스 포트는 8080입니다.

우분투 리눅스에서 젠킨스의 포트를 변경하려면 아래의 파일을 수정해야합니다.

sudo vim /etc/default/jenkins

8080이 기본 포트인데 다른 적당한 포트로 변경해 줍니다.

파일 안에서 아래의 줄을 찾아서 포트를 변경하면 됩니다.

# HTTP_PORT=8080
HTTP_PORT=9090

변경했으면 젠킨스를 재시작합니다.

sudo /etc/init.d/jenkins restart

초간단 Node.js 업그레이드 방법

Linux 서버에 설치된 Node.js를 버전업하는 방법입니다.

요약

  • npm으로 n 이라는 영어 1글자 짜리 이름의 패키지를 설치
  • n으로 stable, lastest 등을 선택해서 원하는 버전으로 업그레이드

stable(안정판), latest(최신판)중에서는 안전하게 stable을 선택하는 것이 좋습니다.

명령어

아래에 적어둔 명령어를 따라서 순서대로 하면 됩니다.
root 권한이 있어야 합니다.

node -v  # node.js 버전 확인
sudo npm cache clean -f  # npm 캐시 삭제
sudo npm install n  # n패키지 설치
sudo n stable  # stable로 설치
# 결과는 아래와 같음
# installed : v16.13.1 (with npm 8.1.2

R언어 Windows에서 한글 메세지가 깨져 보일때

R과 Rstudio를 Windows에서 사용하다보면 한글로 나와야 할 메세지가 깨져 보일 때가 있습니다. 특히 에러메시지나 경고메세지가 보일 때 그렇습니다.

아래 그림에서 보이는 것 처럼 마름모꼴 도형으로 깨져 보입니다.

언어설정을 영어로 변경한다

언어 설정을 영어로 변경하면 영어로는 메세지를 볼 수 있습니다.

Sys.setenv(LANG = "en_US.UTF-8")

윈도우에서 경고 메세지를 한글로 보는 방법은 없다

깨진것을 고쳐서 한글로 보는 방법은 아직 없습니다. 영어로 바꿔서 봐야 합니다. 다음과 같이 모든 메세지를 영어로 변경해주면 됩니다.

원인은 R이 UTF-8을 쓰고 Windows가 euc-kr을 쓰기 때문이다

R은 멀티바이트 언어 즉, 로마 알파벳 계열을 사용하지 않는 언어인 한국어, 중국어, 일본어같은 것을 표현할 때 메세지를 모두 UTF-8을 사용하는데 윈도우는 내부에서 UTF-8을 처리할 수는 있지만 화면에 표현할 때는 무조건 euc-kr를 사용합니다. 애플리케이션에 따라서는 이 문제를 해결한 것들이 있지만 Rstudio는 그 처리를 해주지 않습니다.

그래서 영어로 봐야 합니다.

리눅스 E: Sub-process /usr/bin/dpkg returned an error code (1)

apt를 사용하다보면 에러 메세지가 보일 때가 있습니다.

E: Sub-process /usr/bin/dpkg returned an error code (1)

무슨 종류의 에러인지 메세지만 보고 알기 어려워 해결법 찾기가 어렵지만 알고보면 간단합니다.

설치한 패키지의 의존성이 파손된 것입니다.

다음의 명령으로 의존성 문제가 생긴 것을 해결해주면 됩니다.

sudo rm /var/lib/dpkg/info/*
sudo dpkg --configure -a
sudo apt update -y

리눅스에서 두 CSV파일을 컬럼으로 조인하기 – Joining two text files based on a specific column

리눅스에서 텍스트파일 조인하기

리눅스 코맨드로 csv 2개를 결합하는데 특정 컬럼의 값을 기준으로 조인해서 붙이고 싶을 때가 있습니다.

DB에서 SQL로 조인하는 것처럼 하는 것 말입니다.

리눅스에서 이런 것은 오래전부터 당연히 되지만 명령이 복잡하고 선행 조건이 있습니다. 그래서 외우기 보다는 된다는 것만 알고 스니펫을 적어 두고 찾아서 쓰는 것이 더 편할 수 있습니다.

자세히 봐놓지 않으면 무척 헷갈리고 실제로 해보면 잘 안되기 때문에 천천히 읽어보시기 바랍니다.

조건

언어 설정을 한국어/한글로 바꾸기

우선 파일 안에 한글이 있고 조인을 할 컬럼에 한글이 포함되어 있다면 현재 환경의 언어 설정을 한글로 지정해줍니다. 조인할 파일에 한글이 아예 없으면 안 해도 됩니다.

export LC_ALL="ko_KR.utf8"

파일의 줄바꿈을 CRLF에서 LF로바꾸기

파일을 리눅스나 유닉스에서 생성했다면 문제가 없겠지만 윈도우에서 생성했거나 외부에서 가져왔을 때 텍스트 파일의 줄바꿈 문자를 바꿔줘야합니다.

조인할 두 파일에서 조인에 사용할 컬럼은 모두 정렬되어 있어야합니다. 그것은 명령에서 처리하면 됩니다.

우선 전체 코드는 다음과 같습니다.

#!/bin/bash

# 환경에 언어를 설정하기. 한글 소팅 때문)
$ export LC_COLLATE="ko_KR.utf8"

# 내용 확인
$ cat 1.txt

# 1       홍길동
# 2       전우치
# 4       변학도
# 3       이몽룡
# 5       성춘향

# 내용 확인
$ cat 2.txt

# 성춘향  18세
# 이몽룡  19세
# 전우치  20세

# 결합하기
$ join -t $'\t' -1 2 -2 1 -o 1.1,1.2,2.2 -a1 <(sort -k 2 1.txt | tr -d '\015') <(sort -k 1 2.txt | tr -d '\015') | sort -k 1

# 1       홍길동
# 2       전우치  20세
# 3       이몽룡  19세
# 4       변학도
# 5       성춘향  18세

1.txt는 탭으로 2개의 컬럼이 구분된 파일이고 1번 컬럼은 번호, 2번 컬럼은 사람의 이름입니다.

2.txt는 탭으로 2개의 컬럼이 구분된 파일이고 1번 컬럼은 이름, 2번 컬럼은 나이입니다.

여기에서 하려는 것은 1번의 이름과 2번의 이름을 결합한 다음 1.txt 파일에 컬럼에 나이 컬럼을 하나 추가해서 붙이는 것입니다.

위의 코드에서 마지막 결과물처럼 만들려는 것입니다.

명령어는 아래와 같은데 복잡하므로 분해해서 설명합니다.

join -t $'\t' -1 2 -2 1 -o 1.1,1.2,2.2 -a1 <(sort -k 2 1.txt) <(sort -k 1 2.txt) | sort -k 1

-t $’\t’ : 구분자를 탭으로 하겠다는 것입니다. join 명령어는 구분자를 단일문자만 받기 때문에 \t를 쓰려면 저렇게 앞에 $를 쓰고 따옴표로 둘러싸줘야 합니다.

-1 2 : 이것은 1번 파일에서는 2번째 컬럼을 기준 키로 쓰겠다는 뜻입니다.

-2 1 : 2번 파일에서는 1번째 컬럼을 기준 키로 쓰겠다는 것입니다.

-o 1.1,1.2,2.2 : 출력을 할 때 1.1 (1번째 파일의 1번 컬럼), 1.2 (1번째 파일의 2번 컬럼), 2.2 (2번째 파일의 2번 컬럼)입니다. 콤마로 출력할 컬럼을 구분하고 마침표로 파일 순번과 컬럼 순번을 입력하는 것입니다.

-a1 : 1번 파일을 기준으로 그 다음의 파일을 붙이라는 뜻입니다. 이것을 안 쓰면 결합할 파일에서 출력할 때 키가 겹치는 것만 남습니다. SQL에서는 이너조인(inner join)과 같이 됩니다. 이 옵션을 빼고 실행해 보시면 차이를 금방 알 수 있습니다.

<(sort -k 2 1.txt) : 1번 파일을 컬럼 2번을 기준으로 정렬하라는 것인데 <를 앞에 붙이고 소괄호로 둘러싼 것은 정렬된 파일을 미리 만들지 않고 동적으로 정렬하기 위한 것입니다.

<(sort -k 2 1.txt) : 위에서 설명했습니다.

sort -k 1 : 결과물을 다시 1번 컬럼을 기준으로 정렬합니다.

리눅스에서 한글 파일 정렬이 안될 때 – Sorting Korean text file on Linux

다음과 같은 파일이 있습니다.

파일이름은 test.txt입니다.

1       홍길동
2       전우치
4       변학도
3       이몽룡
5       성춘향

이렇게 하면 2번째 커럼으로 소팅이 되야 합니다.

sort -k 2 test.txt


그런데 이렇게 해도 소팅이 안되고 순서가 정렬이 안되는 경우가 있습니다.

LC_COLLATE나 LC_ALL 환경변수에 한글을 지정해 줘야 합니다.

$ export LC_COLLATE="ko_KR.utf8"
# 또는
$ export LC_ALL="ko_KR.utf8"

위의 명령으로 리눅스 환경의 언어셋을 변경하면 소팅이 되는데 에러 메세지가 나올 수 있습니다.

-bash: warning: setlocale: LC_COLLATE: cannot change locale (ko_KR.utf8): No such file or directory

이 에러가 나오는 것은 언어패이 설치가 되어 있지 않기 때문입니다. 그럴 때는 이렇게 해줍니다.

# CentOs나 Redhat 리눅스 계열
$ sudo apt install language-pack-ko

# Ubuntu 우분투 계열
$ sudo yum install glibc-langpack-ko

그 뒤에 다시 sort 코맨드로 정렬을 해보면 잘 됩니다.

$ sort -k 2 1.txt

4       변학도
5       성춘향
3       이몽룡
2       전우치
1       홍길동

데이터과학자가 되려면 뭘 배워야 하나?

데이터과학자가 되기 위해서 필요한 것들이라는 주제로 포스트를 몇개 작성하였었지만 더 간략한 것을 원하는 분들이 많다는 것을 알았습니다.

간단하게 말하면 지금은 아래의 4가지입니다.

  1. SQL
  2. R 또는 Python 언어
  3. Linux (리눅스)
  4. Algebra (수학)

여기에서 SQL, R, Python, Linux는 다해서 1 ~ 2년 배운다면 기초적인 일을 할 수는 있습니다. 그게 그렇게나 오래 걸리나? 라고 생각하실 지 모르겠지만 그렇게 만만한 것들 아닙니다.

SQL은 책 보고 SQLd 자격증 준비하면서 같이 공부하세요.

R, Python은 책 읽고 인터넷 강좌 들으세요. 그리고 코드 따라하기를 여러 번 해보세요.

Linux도 책 사서 보거나 인터넷 자료 뒤져 보시고, 인터넷 강좌 보고 그 후에 연습을 하면 됩니다.

문제는 수학입니다. 수학은 선형대수학, 미적분, 미방까지 해야 하고 논리적 사고방식과 숫자를 다루는 연습까지 되야 하기 때문에 속성으로 훈련이 안됩니다.

그리고 결국 나중에 좋은 기계학습모델을 만들거나 좋은 수리 모형을 만들 수 없게 되고 역량이 떨어지게 됩니다. 결국 본인의 몸값도 높일 수 없게 됩니다. 인터넷 강의 들으면서 날마다 무지막지하게 공부하시면 됩니다.

물론 수학을 원래 잘하는 분들은 괜찮겠습니다만 그런 분들 별로 없습니다.

각종 AI 프레임워크 별로 GPU 사용 가능 확인하기

Tensorflow, Keras, Torch에서 각 버전과 GPU를 사용할 수 있는지를 알아내는 코드입니다.

GPU가 장착된 서버 또는 데스크탑에서도 Nvidia 드라이버와 CUDA를 제대로 설치하지 않아서 사용을 못하는 경우가 많습니다.

GPU가 있고 또 사용할 일이 있을 것 같다면 확인을 하고 시작하는 것이 좋습니다.

# 립러링 프레임워크들의 버전과 GPU 확인

# 1. Tensorflow
import tensorflow as tf
print("Tensorflow version: {}".format(tf.__version__))
print("Tensorflow GPUs: {}".format(tf.test.is_gpu_available(
    cuda_only=False,
    min_cuda_compute_capability=None
)))
from tensorflow.python.client import device_lib
print("Tensorflow device list: {}".format(device_lib.list_local_devices()))

# 2. Keras
from keras import backend as K
import keras
print("Keras version: {}".format(keras.__version__))
print("Keras GPUs: {}".format(K._get_available_gpus()))

# 3. PyTorch
import torch
print("Torch device count: {}".format(torch.cuda.device_count()))
print("Torch device name: {}".format(torch.cuda.get_device_name(0)))
print("Torch CUDA is available: {}".format(torch.cuda.is_available()))

결과는 이런 식으로 나옵니다.

Tensorflow version: 2.6.0
Tensorflow GPUs: True
Keras version: 2.6.0
Keras GPUs: ['/device:GPU:0', '/device:GPU:1']
Torch device count: 2
Torch device name: NVIDIA GeForce RTX 3080
Torch CUDA is available: True

python tensorflow 에러 get_config

Python 노트북에서 Keras, Tensorflow로 작업을 하다가 패키지를 업데이트하거나 해서 GPU 설정을 잘못하면 다음가 같은 에러가 납니다.

cannot import name 'get_config' from 'tensorflow.python.eager.context' (/usr/local/lib/python3.8/dist-packages/tensorflow/python/eager/context.py)

해결책은 그냥 tensorflow gpu 버전을 같이 설치해 주면 됩니다.

pip install --upgrade tensorflow
pip install --upgrade tensorflow-gpu

기계학습과 딥러닝의 차이 – Difference Machine learning with Deep learning

기계학습, AI, 딥러닝을 구별하려면 알고리즘의 히스토리를 알아야 하기 때문에 공부하지 않고 직관적으로 이해하기 어렵습니다.

기계학습 Machine Learning

기계학습, Machine Learning, 머신러닝, ML 이라는 용어로 통용됩니다.

기계를 학습시켜서 반복적인 작업을 하게 만드는 것을 기계학습이라고 합니다. 이 때 학습이라는 것은 데이터를 넣고 데이터에 있는 패턴을 알아내서 패턴으로 부터 규칙이나 사실을 알아내고 그것을 그대로 다시 활용하는 것을 말합니다.

여기에서 데이터는 결국 숫자들의 뭉치이고 패턴이라는 규칙도 결국 숫자들입니다.

패턴을 어떻게 알아내느냐는 여러가지 방법이 있습니다. 통계학자들이 만들어낸 통계적인 알고리즘, 수학자들이 만들어낸 수학적인 알고리즘 등이고 이것들을 활용해서 만든 SVM, Decision Tree, Logistic Regression, Neural Network 등과 같은 오래된 유명한 알고리즘들이 있습니다.

이 중에 Neural Network (인공신경망, 뉴럴네트워크, NN)이라는 것이 있는데 이것과 SVM과 같은 고차원 문제를 다루는 몇가지 수학적인 알고리즘 따로 구분해서 따서 AI라고 따로 분리합니다.

그리고 인공지능이라는 쪽으로 협소하게 구분해서 AI라고 합니다.

인공지능 AI

인간의 뇌를 모방한 후 알아서 스스로 작동하게 하는 모든 것을 AI라고 합니다. 게임할 때 사람과 싸우는 가상의 존재들도 AI라고 부릅니다. AI는 기본적으로 알고리즘을 이용해 만든 소프트웨어와 데이터 뭉치들입니다. 앞서 설명한 기계학습의 일종입니다.

뉴럴네트워크, Neural Network, 인공신경망

인공신경망은 인간의 뇌구조를 모방한 것인데 임의로 만들어 놓은 많은 숫자들과 함수들을 배열해 놓고 데이터를 흘려 보내서 이 숫자들을 데이터의 규칙에 맞는 최적으로 숫자로 맞추게 됩니다.

그리고 이 숫자들을 나중에 활용할 때 씁니다.

흔히 예로 많이 쓰는 고양이 사진과 멍멍이 사진을 구분하게 만드는 것도 마찬가지입니다. 사진을 넣으면 사진을 조각내서 색생과 밝기 같은 것을 숫자들로 만들고 이 숫자들을 뉴럴네트워크라는 수학적인 모델에 무수히 많이 반복해서 흘려 넣습니다. 그러면 뉴럴네트워크 내에서 고양이 사진과 개 사진을 구별할 수 있는 숫자 뭉치가 나옵니다.

딥러닝, Deep Learning

뉴럴네트워크가 다 좋은데 2가지 큰 문제가 있었습니다.

첫번째, 연산을 너무 많이 한다는 것. 그러니까 CPU와 메모리를 너무 많이 쓰고 시간도 오래 걸립니다.

두번째, 숫자를 만들어 내는 층을 많이 만들면 모델이 엉망이 된다는 것입니다. 은닉레이어라고 하는데 이 층을 많이 만들 수 없었습니다.

그런데 2010년 전후로 이 알고리즘이 대격변이 일어납니다. 알고리즘의 결함을 크게 개선했고 GPU와 같은 하드웨어의 급속적인 발전으로 이 숫자 뭉치를 만들어내는 층을 더 깊게 할 수 있고 더 많이 더 빠르게 할 수 있게 되었습니다.

그 뒤 이 숫자를 찾아내는 층이 더 깊어졌고 알고리즘으로 만들어낸 모델들의 정확도가 비약적으로 높아졌습니다.

이것을 딥러닝, 심층학습이라고 부릅니다.

현재의 대세는 딥러닝

데이터와 GPU가 많다면 현재는 가장 정확한 것은 딥러닝입니다.

인공지능, 자율주행, 가상현실, 게임, 대부분의 영역에서 덥러닝은 가장 활발하며 아직도 급속도로 발전하고 있습니다.

딥러닝은 뉴럴네트워크의 개선형이며 딥러닝을 만든 사람이 뉴럴네트워크의 이미지가 너무 안좋아서 다른 이름을으로 불리길 원했을 뿐 실제로는 같은 계열입니다.

하지만 여전히 많은 부분에서 전통적인 ML 기술도 쓰이고 있고 여전히 유용합니다. 예를 들어 사람의 신용평가와 같은 기계학습 모델에 딥러녕을 쓸 필요도 없고 잘 되지도 않습니다. 데이터가 충분하지 않기 때문에 이런 것은 데이터가 부족해도 잘 돌아가는 융통성있는 알고리즘이 필요하기 때문입니다.

어쨌든 경우에 따라 ML도 하고 AI도 하게 되는데 그래서 이런류의 기술을 ML/AI 라고 합쳐서 많이 부릅니다.

Ubuntu 패키지 업데이트 에러: dpkg: error processing package update-notifier-common (–configure):

Ubuntu에서 패키지를 업데이트 하는 도중에 다음과 같은 에러 메시지를 보는 경우가 있습니다.

이거 생각보다 잘 복구가 되지 않는데요.

dpkg: error processing package update-notifier-common (--configure):

여러가지 방법을 써봤지만 잘 안되고 가장 확실한 것은 다음과 같이 하는 것입니다.

cd /var/lib/dpkg
sudo mv info info.bak
sudo mkdir info
sudo apt-get upgrade

Python Torch로 CUDA , GPU 사용가능 여부 확인하기

GPU를 사용하기 위해서는 드라이버를 설치하고 몇가지 작업을 해줘야 합니다.

Python에서 GPU를 쓸 수 있게 되어 있는지 아닌지 확인할 때 pytorch를 쓴다면 다음과 같이 하면 됩니다.

import torch

print("쿠다 가능 :{}".format(torch.cuda.is_available()))
print("현재 디바이스 :{}".format(torch.cuda.current_device()))
print("디바이스 갯수 :{}".format(torch.cuda.device_count()))

for idx in range(0, torch.cuda.device_count()):
    print("디바이스 :{}".format(torch.cuda.device(idx)))
    print("디바이스 이름 :{}".format(torch.cuda.get_device_name(idx)))
    

결과는 이런식으로 나옵니다.

쿠다 가능 :True
현재 디바이스 :0
디바이스 갯수 :2
디바이스 :<torch.cuda.device object at 0x7fd3cd576460>
디바이스 이름 :GeForce RTX 3080
디바이스 :<torch.cuda.device object at 0x7fd3cd5766d0>
디바이스 이름 :GeForce GTX 1080

Gensim 사용 오류 – ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObject

오랜만에 Gensim을 설치해서 사용하려고하니 오류가 나옵니다.

ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObject

number의 ndarray 사이즈가 바뀌었다는 오류메세지인데 해결책은 간단합니다.

numpy를 다시 설치하면 됩니다.

pip uninstall numpy
pip install numpy

추가로

numpy는 매우 중요한 패키지이기 때문에 가능하면 최신으로 유지하는 것이 좋습니다. 하지만 일부 ML/AI 패키지들이 numpy 구버전을 요구하는 경우가 있습니다.

이런 경우는 뚜렷한 해결책은 없습니다. 그냥 낮은 버전의 numpy를 사용하는 패키지를 제거하는 것이 좋습니다.

무료 책 – R 패키지 제작 방법

R패키지는 만드는 것이 까다롭습니다.

패키지를 코딩해서 만드는 것도 어렵지만 CRAN에 등록할 때 어려운 점이 많습니다.

R패키지를 만들때 어려운 점

  • 여러가지 제약 사항과 고려 사항을 미리 처리해 둬야 해서 경험이 많아야 함
  • CRAN의 관리자에게서 잦은 지적사항과 관리자의 고압적인 지시사항으로 인한 스트레스와 감정 소포

R패키지를 만들어서 혼자만 쓰거나 특정 그룹 또는 회사내에서만 쓰는 것이면 CRAN에 등록하지 않아도 됩니다.

하지만 예전부터 R패키지를 만드는 사람들은 명예의 징표처럼 만든 패키지를 CRAN에 등록하는것이 목표이며 자랑거리로 생각해 왔습니다.

CRAN에 등록하기 전에 패키지를 만드는 법을 배우려면 공부가 필요합니다.

그래서 소개해 드릴 책은해들리 위캠이 쓴 R 패키지 책입니다. 온라인 버전은 무료입니다. 해들리 위캠 교수는 ggplot2를 만든 R언어의 대스타입니다.

https://r-pkgs.org/

이 책은 R언어로 패키지를 만들 때 알아야 할 내용을 간결하게 설명하고 있습니다.

R 패키지 제작에 관심이 있다면 읽기를 추천합니다.

영어로 작성되어 있어 영어 울렁증이 있다며 안 볼 수도 있지만 크롬에서 열어서 한글 번역 버튼을 눌러서 보면 내용을 그럭저럭 볼 수 있습니다. 요즘 구글 번역기가 정말 많이 좋아졌다고 생각합니다. 영어에 자신이 없어도 시도해 보세요.

빅데이터는 사기?

“빅데이터는 사기다”라고 구체적인 근거없이 맹목적으로 비난하는 분이 많아서 이 글을 포스팅합니다.

두괄식으로 말하면

빅데이터는 그 자체로는 사기가 아닙니다.

빅데이터로 사기를 치면 그게 사기이지요

빅데이터는 사기라고 말하는 사람이 많습니다. 실제 현장의 실정을 알기 때문에 이런 말 을 하는 분들이 무슨 뜻으로 하는 얘기인지 이해가 됩니다만 하지만 그렇다고 해서 그 모든 것이 다 사실이 아니거나 너무 왜곡하는 경향도 많습니다.

빅데이터가 사기라고 말하는 이유는 아마도

다음과 같이 일을 처리했거나 그걸 옆에서 지켜본 뒤의 경험을 얘기했을 것입니다.

  • 빅데이터 프로젝트 또는 PoC를 진행 했는데 뭘 했는지 모를 결과가 나왔을 때
  • 빅데이터의 성과보다는 ”빅데이터 프로젝트”라는것을 해보고 싶은 목적으로 프로젝트를 진행했을때
  • 할일이 없어서 “이거라도 해보자고 하자”라고 막연히 진행했을 때
  • 예산과 리소스를 사용하고도 실제로 비즈니스나 매출에 영향이 전혀 없을 때

빅데이터는 과정 또는 수단이지 결과가 아니다.

빅데이터 자체가 목표인 비즈니스는 빅데이터 플랫폼, 솔루션을 판매하거나 기술지원 상품을 판매하는 회사가 아니라면 많은 회사들에게 빅데이터는 “수단”입니다.

대부분의 회사, 연구소에게 빅데이터는 목표가 아닙니다. 차분히 새각해보면 그런 말이 많이 이상하다는 생각에 동의하실 것입니다.

빅데이터의 가장 활용도는 빅데이터를 이용해서 비즈니스를 개선하거나, 비즈니스 아이템을 발굴하거나, 비즈니스에 중요한 결정을 하는데 필요한 데이터를 처리하고 인사이트를 찾는 것을 돕는 것입니다.

디때 데이터 사이즈가 작고 처리하기 어렵지 않으면 그냥 통계분석이나 데이터과학이 되는 것이고 데이터 사이즈가 매우 크고 처리량도 많고 일도 많다면 빅데이터 분석, 빅데이터를 사용한 데이터 과학이 되는 것입니다.

물론 잘 아시다시피 인공지능, 기계학습에 필요한 데이터를 처리하는데도 빅데이터가 필요합니다.

빅데이터 그거 해봤는데 결과가 안좋드라.

어느날 대형 이커머스 A사와 미팅에 들어갔는데 빅데이터 해봤더니 결과가 안좋아서 우리는 사기라고 생각한다고 하더군요.

그래서 무슨 결과가 어떻게 안 좋았냐고 물었습니다. 담당자가 그냥 밑도끝도 없이 좋은 결과가 안 나왔다는 말만 되풀이하는 것이었습니다.

이 회사 뿐만은 아니고 다른 회사들과 비팅에서도 다수가 비슷한 반응이었습니다. 넘겨짚어 해석을 해보면 대부분 다음과 같은 이유입니다. 사실은 결정권자 진행자 들이 빅데이터 자체를 못마땅해 하는 것입니다.

그냥 하기 싫은 것이지요.

  1. 회사의 매출에 도움이 되는 전술을 빅데이터 프로젝트로 도출을 못했다. 즉 사업개선 아이템이나 사업확장 아이템을 못 내놨다.
  2. 인프라로 구축한 빅데이터가 돈만 쓰고 매출이나 이익을 올리는데 기여를 못한다. 돈만쓰고 돈을 못벌었다.
  3. 기술우위를 논할만큼 대단한 기술이 아니다.
  4. PoC를 했는데 결과물(산출물)이 소프트웨어가 아니고 문서쪼가리다.

이 외에도 더 많습니다만 위의 것만 하나씩 대답을 해보자면

1번 회사의 매출은 경영진이 책임져야지

회사의 매출을 올리는 것은 영업, 기획, 마케팅, 경영진이 하는겁니다. 빅데이터는 과학적 근거를 찾거나 인사이트를 찾는데 사용하는 도구입니다. 빅데이터가 그걸 해주면 그 회사 대표이사와 기획부서는 왜 필요한가요?

2번 인프라인데 돈만 쓰고 나오는게 없어

그럼 회사에서 사용하는 데이터베이스, 더존 회계, IT지원부서, 인사팀 사람들은 왜 필요한가요?

인프라는 효율을 위해서 필요한거지 당장의 매출을 올리려고 하는 것이 아닙니다.

이 질문 하는 사람들은 99%가 기술이나 생산부서 사람들입니다.

3번 그게 뭐 대단한 기술인가?

태초에는 대단한 기술이었지만 지그은 그렇게 대단한 기술이 아닌 것은 사실입니다. 누구나 다 하니까요.

그렇다고해서 전혀 쓸모 없는 것은 아닙니다. 여러분이 사용하는 대부분의 최신 데이터 처리, 분석 시스템은 빅데이터 플랫폼입니다.

4번 빅데이터를 했으면 어떻게 작동하는지 보여줘봐

대부분의 빅데이터 프로젝트는 빅데이터 플랫폼 도입 아니면 인사이트 도출입니다.

플랫폼 도입는 PoC를 해서 요건은 만족하면 도입하는 것이고 안시이트 도출은 인사이트가 나올 수도 있고 안나올 수도 있고 나왔는데 뻔한 것일 수도 있습니다.

빅데이터 프로젝트는 대부분 소프트웨어 개발이 아닙니다.

빅데이터 사기란 무엇인가?

”빅데이터를 하면 무조건 회사 매출이 오르고 주식이 2배로 뜁니다.” 라고 말하면 사기입니다.

대부분 그렇게 말하지 않지요. 진짜 사기꾼이라도 그렇게는 말 안합니다.

사기는 사기 행위가 드러나야 사기인 것입니다. 자기 마음에 들지 않거나 자기가 프로젝트에서 소외되고 회사가 헛돈 쓰는 것 같아서 마음에 들지 않는다고 사기라고 말하는 것도 올바른 생각은 아닙니다.

“빅데이터라는사탕발림으로 경영진과 결정권자를 홀려서 눈먼 돈을 뜯어간 것이 아니냐?” 라고 물을 수도 있을 것입니다.

이럿게 되물을 수 있습니다.

  • 그렇다면 대부분의 경영 컨설턴트들은 그렇지 않단 말입니까? 그들도 말로 사탕발림하는 것은 똑같지 않습니까?
  • 그렇다손 치더라도 과연 경영진과 결정권자들이 그걸 몰랐을까요? 그렇게 멍청할까요?

대부부 이 질문에 대한 답을 하지 못합니다.

빅데이터는 사기다라고 말하는 사람의 두 부류

두 부류입니다.

  • 빅데이터를 전혀 모르는 사람
  • 빅데이터를 너무 잘하는 사람

개인적인 통계를 내보면 99%가 빅데이터를 전혀 모르는 사람입니다.

옆에서 지켜보는 것이 전부는 아니라는 말을 해두고 싶습니다.

특히 소프트웨어 개발자들은 데이터 활용에 대해서 무지한 사람이 매우 많습니다. 본인들은 이런 말을 들으면 매우 불쾌해 하지만 현실은 그렇습니다.

그 사람들은 데이터과학자들이 자신들보다 높은 급여를 받으며 결정권자와 친밀하고 말로 자신들을 압도하는 것에 대해서 매우 불편해 합니다.

경험으로 볼 때 보통 빅데이터는 사기다라고 말하는 사람들의 90%가 개발자들이고 나머지 10% 자기가 할 일이 늘어나는 일하기 싫어하는 회사 직원들입니다.

구글 빅쿼리는 무엇인가? What is Google BigQuery

빅쿼리 BigQuery를 짤막한 문장으로 쉽게 설명해 봤습니다.

개념

  • 구글이 만들어서 제공하는 서비스입니다. 유료입니다.
  • 데이터베이스라고 이해하면 됩니다.
  • 빅데이터 플랫폼입니다.
  • SQL 언어를 사용해서 사용할 수 있습니다. (이름에 Query가 들어간 것을 볼 수 있음)
  • 초대량 데이터 분석용 솔루션입니다.
  • 실시간 솔루션은 아닙니다. 하지만 실시간 지원을 일부 합니다.
  • BI/DW의 엔진으로 많이 씁니다.

요금

  • 사용료는 종량제와 정량제로 나눌 수 있는데 기본은 종량제 즉 쓰는 만큼 지불합니다.
  • 데이터를 스캔한 만큼. 즉, 스토리지에서 빅쿼리가 데이터를 읽은 만큼 과금합니다. 1Tb를 읽어들이게 하면 5달러정도의 요금을 지불
  • 합니다.

누가 쓰나?

  • 데이터 과학자 Data Scientist
  • 데이터 분석가 Data Analyst
  • 데이터 엔지니어 Data Engineer

좋은점

  • 많은 사용자들이 빅쿼리 데이터 집계나 처리가 매우 빠르다고 말합니다. 하둡, 스파트 등의 다른 빅데이터 플랫폼에 비해서 말입니다.
  • 쓰는 만큼만 요금을 내면 됩니다.

나쁜점

  • 아무생각없이 쓰면 요금이 매우 많이 나올 수도 있습니다. 1회 쿼리에 수십만원에서 수백만원을 쓰는 경우도 있습니다.
  • 사용법 및 다루는 법이 어렵지는 않지만 훈련과 연습이 필요합니다.

그외에

  • 대부분의 데이터과학자가 선호하는 솔루션입니다.
  • 데이터 엔지니어들은 좋아하는 사람과 싫어하는 사람들이 반반정도 되는 것 같습니다.

Python 에러 해결 – TypeError: a bytes-like object is required, not ‘str’

이 에러는 아는 사람에게는 너무 쉽고 해결하기에 간단한 것이지만 모르면 삽질하기 쉬운 에러입니다.

참고를 위해서 포스팅합니다.

파이썬에서 문자열을 다루다 보면 이런 에러가 나올 때가 있습니다.

TypeError: a bytes-like object is required, not ‘str’

이 에러는 사용하려고 하는 곳에는 bytes-likes 오브젝트가 필요하니 str 타입을 넣지 말고 bytes 타입의 변수를 넣으라는 뜻입니다.

즉 bytes 타입의 변수를 전달해줘야 하는 곳에 str 타입을 줬기 때문입니다.

이 에러는 DB나 다른 플랫폼, 시스템에서 당겨온 데이터안의 문자열을 처리하다보면 만날 때가 있습니다.

bytes와 str은 다음과 같은 관계가 있습니다. 바꾸는 방법입니다.

  • str –> 디코딩 –> bytes
  • bytes –> 인코딩 –> str

코드로 바꾸면 이렇게 하면 됩니다.

text = "안녕"  # text는 str이 됩니다.
text_byte = text.encode('utf-8')
text_str = text_byte.decode('utf-8')

에러메세지에 bytes라는 단어가 보이면 대부분 문자열 인코딩, 디코딩과 관련이 있을 것이라고 기억하면 됩니다.

VS code나 Pycharm 같은 개발툴에서 지원하는 힌트를 보고 어떤 타입의 변수가 필요한지 확인하고 적절한 에러를 처리해 주는 것도 좋은 습관입니다.

리눅스에서 코맨드라인으로 구글 드라이브 사용하기 – Using Google Drive in command-line

리눅스에서 구글드라이브를 사용하는 방법입니다.

리눅스에서 구글드라이브를 사용하려면 여러가지 방법을 쓸 수 있지만 이 글에서는 GUI나 네트워크드라이브 마운트 방식이 아닌 코맨드라인(command line) 명령어를 사용하는 방법입니다.

즉 리눅스 서버에서 Google Drive를 연결해서 파일을 업로드하거나 다운로드 하기위한 것입니다.

리눅스에서 Google Drive를 사용하는데는 여러 용도가 있습니다.

용도

배치 프로세싱

구글 드라이브에서 데이터를 받아서 AI/기계학습 모델을 만들때 씁니다. 학습 데이터는 대부분 용량이 큽니다.

만들어진 추출된 데이터를 누군가에게 전달해야 할 때 씁니다. 데이터 분석을 위해서 추출한 데이터 중에 사이즈가 상당히 큰 것도 있습니다. 이걸 리눅스 서버에서 처리한 뒤에 결과물을 업로드할 때 씁니다.

데이터 백업을 잠시 할 때도 씁니다. 물론 더 안전하고 괜찮은 데이터 백업 방법이 많이 있습니다만 임시 작업이나 급한 작업을 할 때는 꽤 유용합니다.

설치

gdrive 다운로드받기

코맨드라인에서 쓸 수 있는 구글드라이브 공식패키지는 없습니다.

대신 아래의 github에서 받으면 됩니다.
https://github.com/prasmussen/gdrive

실행파일은 위의 페이지를 읽다보면 밑의 페이지로 이동해서 받으라고 합니다. 적당한 것을 받습니다.

https://github.com/prasmussen/gdrive/releases

저는 vm을 사용하기 때문에 32bit 버전을 받습니다. vm들이 보통 32bit OS이기 때문입니다. 64bit라면라면 AMD64가 이름에 포함된 것을 받으세요. 만약 실행이 안되면 32bit버전을 64bit os에서 그냥 쓰셔도 됩니다. 그리고 압축을 풀고 나온 gdrive실행파일을 /usr/local/bin 아래로 옮겨줍니다.

wget https://github.com/prasmussen/gdrive/releases/download/2.1.1/gdrive_2.1.1_linux_386.tar.gz

구글 인증하고 백업 파일을 업로드하기

이제 gdrive 실행을 해봅니다.
먼저 구글드라이브에 있는 파일 리스트를 봅니다.

gdrive list

Google 인증을 하라는 메세지가 나오게 됩니다.

Authentication needed# Go to the following url in your browser:# https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=367116221053-7n0vf5akeru7on6o2fjinrecpdoe99eg.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&state=state

웹브라우저를 실행하고 위에서 나온 URL을 주소창에 붙이고 인증을 합니다. 그러면 아래처럼 코드를 줍니다. 코드를 다시 코맨드 창으로 돌아와서 붙여 넣으면 됩니다.

이제 파일을 구글 드라이브에 폴더를 만들어서 백업해 봅니다.

gdrive mkdir __백업
# Directory 1l0nTwWhHSONxltMbplI9XEhR2TxnPf45 created

디렉토리를 생성하고 디렉토리 아이디를 알려주는데 업로드할 때 폴더명을 사용하지 않고 디렉토리ID를 사용하므로 저것을 복사해 둡니다. 나중에 gdrive list 코맨드로 알아낼 수도 있습니다.

아래와 같이 파일을 업로드 하면 됩니다. backup.tgz이라는 파일을 “__백업”이라는 구글드라이브 폴더에 업로드하는 것입니다.

gdrive upload --parent 1l0nTwWhHSONxltMbplI9XEhR2TxnPf45 backup.tgz

참조

Using Google Drive from the Linux Command Line