우분투(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