반응형

안녕하세요.

이번에는 한국어 데이터셋을 가지고 gensim을 사용한 LDA 토픽 모델링 실습을 해보도록 하겠습니다.

 

데이터 준비

테이터셋으로 '청와대 국민청원' 에 만료된 청원 데이터를 사용하도록 하겠습니다.

아래 사이트 접속 후 

https://github.com/akngs/petitions

 

GitHub - akngs/petitions: 청와대 국민청원 데이터

청와대 국민청원 데이터. Contribute to akngs/petitions development by creating an account on GitHub.

github.com

petition_sampled.csv 를 클릭하여 다운받아 주세요.

전체 데이터는 데이터 용량이 커서 샘플 데이터를 사용하겠습니다.

 

파일 불러오기

다운받은 파일중 5개만 예시로 출력해보겠습니다.

import pandas as pd
df = pd.read_csv('petition_sampled.csv')
df.head()

데이터는 위와 같이 구성되어 있는 것을 확인할 수 있습니다.

여기서 실습에서는 청원 내용을 가지고 토픽 모델링을 해보도록 하겠습니다.

때문에 content컬럼만 따로 뽑아줍니다.

contents = df['content']
contents

또한 원본 데이터에 카테고리 항목이 있는데 

데이터가 몇 개의 카테고리가 있는지도 한번 확인해 보겠습니다.

groupby를 사용하여 카테고리가 몇 개 있는지 확인해 보겠습니다.

len(df.groupby('category').votes.sum())

이렇게 17개의 카테고리가 있는 것을 확인할 수 있습니다.

참고로 가장 많은 votes 수의 카테고리는 '인권/성평등' 카테고리임을 확인할 수있습니다.

 

 토픽 모델링을 위한 텍스트 토큰화(형태소분석)하기

여기서는 Gensim을 사용하여 LDA 토픽 모델링을 해 볼 건데요,

gensim을 사용하면 혼란도와 토픽 응집도를 간단하게 구할 수 있어 많이 사용됩니다.

pip install gensim

을 터미널에 입력하여 설치할 수 있습니다.

gensim은 입력값으로 텍스트를 그대로 입력하는 것이 아닌 토큰화된 결과를 입력값으로 사용하므로

청원 내용을 형태소 분석을 통해 토큰화 해보도록 하겠습니다.

형태소 분석으로는 konlpy의 Okt를 사용하여 분석해 보겠습니다. 

단어 중 '명사' 및 2글자 이상의 단어만 추출해 보도록 하겠습니다.

from konlpy.tag import Okt
###형태소 분석###
okt = Okt()
def analysis_pos(text):
    morphs = okt.pos(text,stem=True)

    words = []
    #명사 추출, 2글자 이상 단어 추출
    for word, pos in morphs:
        if pos == 'Noun':
            if len(word) > 1:
                words.append(word)
    return words

texts = [analysis_pos(news) for news in contents]

이렇게 함수를 만들어 texts 변수 안에 토큰화한 텍스트를 저장하였습니다.

 

토큰화 된 텍스트로 gensim Dictionary 만들기

gensim LDA에서 id2word에 사용하기 위해 토큰화된 텍스트로 사전을 만들어 보겠습니다.

from gensim.corpora.dictionary import Dictionary
# 형태소 분석으로 토큰화 후 dictionary 생성
dictionary = Dictionary(texts)
print("#문서에 있는 단어 수: %d개"%len(dictionary))

문서에 있는 단어 수가 3만개가 넘는데요,

이를 filter_extremes를 사용해 단어를 2000개까지 설정하고 5개 미만으로 나온 단어는 제외, 전체 50% 이상으로 많이 나오는 단어들도 제외를 해보도록 하겠습니다.

keep_n 으로 단어 갯수를 설정하고, no_below로 일정 횟수 미만으로 나온 단어는 제외, no_above로 일정 비율 이상으로 나오는 단어들도 제외하도록 설정할 수 있습니다.

물론 다른 비율 또는 횟수, 갯수로 바꿔서 필터링 할 수 도 있습니다.

# 너무 많은 단어나 너무 적은 단어를 제외하고, 단어 빈도순으로 정리
dictionary.filter_extremes(keep_n=2000, no_below=5, no_above=0.5)
print("#너무 많은 단어 및 적은 단어를 제외하고 문서에 남아 있는 단어 수: %d개"%len(dictionary))

카운트벡터로 변환하기

gensim LDA 에 사용하기 위한 corpus를 생성하려면 doc2bow를 사용하여 카운트 벡터로 변환하여야 합니다.

gensim에서는 토큰화 된 결과를 texts라 하고 이것을 카운트 벡터로 변환한 것을 corpus라고 합니다.

# 카운트 벡터로 변환
corpus = [dictionary.doc2bow(text) for text in texts]
print("#최종적으로 문서에 있는 단어 수: %d개"%len(dictionary))
print("#카운트 벡터 수: %d개"%len(corpus))

Gensim LDA 모델 생성

gensim의 LdaModel을 사용해서 LDA 모델링을 수행할 수 있습니다.

num_topics은 토픽의 수를, passes는 말뭉치 전체를 학습하는 횟수, corpus는 토큰화한 값들을 카운트 벡터화 한것, id2word는 위에서 만든 dictionary를 입력하면 됩니다.

우선 원본 데이터가 총 17개의 카테고리를 가지고 있으므로,

num_topics를 17로 설정하여 모델링을 수행해 보도록 하겠습니다.

from gensim.models import LdaModel
num_topics = 17
passes = 5
model = LdaModel(corpus=corpus,id2word=dictionary,\
    passes=passes, num_topics=num_topics,\
        random_state=7)

그 후 모델링 한 결과를 각 토픽당 10개의 단어씩 뽑아서 보도록 하겠습니다.

model.print_topics(num_words=10)

pyLDAvis를 사용한 시각화

위의 모델링 결과를 한눈에 보기 쉽게 pyLDAvis를 사용하여 시각화할 수 있습니다.

설치는 pip install pyLDAvis 로 설치 가능합니다.

import pyLDAvis
import pyLDAvis.gensim_models as gensimvis
pyLDAvis.enable_notebook()

#LDA모형 시각화
lda_visual= gensimvis.prepare(model,corpus,dictionary)
pyLDAvis.display(lda_visual)

최적의 토픽 수 선정하기

원본이 17개 카테고리여서 num_topics를 17로 설정했지만 실제 분석시에는 카테고리조차 없는 데이터들도 있을 것입니다. 

또한 위의 결과도 최적의 토픽 개수를 설정한 것인지 알 수 없으므로 혼란도와 토픽응집도를 구해서 살펴보도록 하겠습니다.

gensim에서 .log_perplexity를 사용하면 혼란도를, CoherenceModel로 토픽응집도를 간편히 구할 수 있습니다.

여기서는 혼란도와 토픽 응집도를 구하는 함수를 만들고

for문을 사용하여 토픽 갯수당 각각의 혼란도, 응집도를 구해 그래프로 시각화 후 최적화를 진행해보겠습니다.

import matplotlib.pyplot as plt
from gensim.models import CoherenceModel
def coherences(corpus, dictionary, start=6,end=15):
    iter_num=[]
    per_value=[]
    coh_value=[]
    for i in range(start, end+1):
        model = LdaModel(corpus=corpus, id2word=dictionary,
                        chunksize=1000, num_topics=i,
                        random_state=7)
        iter_num.append(i)
        pv = model.log_perplexity(corpus)
        per_value.append(pv)
        CM = CoherenceModel(model=model, corpus=corpus, coherence='u_mass')
        coherence_value = CM.get_coherence()
        coh_value.append(coherence_value)
        print(f'토픽 수: {i}, 혼란도:{pv:0.3f}, 응집도: {coherence_value:0.3f}')
        
    plt.plot(iter_num,per_value,'g-')
    plt.xlabel("num_topics")
    plt.ylabel("perplexity")
    plt.show()
        
    plt.plot(iter_num, coh_value,'r--')
    plt.xlabel("num_topics")
    plt.ylabel("coherence")
    plt.show()

start는 토픽의 시작 갯수를, end는 마지막으로 구할 토픽 갯수입니다.

간단히 말해 for문의 시작과 끝을 설정한다고 볼 수 있습니다.

여기서는 토픽 5개~20개까지로 설정했을 때 각각의 혼란도, 토픽 응집도를 구해 보겠습니다.

coherences(corpus, dictionary, start=5,end=20)

혼란도는 낮을 수록 좋고 토픽 응집도는 0에 가까울수록 좋습니다.

위의 그래프를 보면 혼란도가 가장 낮게 나타난 곳은 17개이고, 토픽 응집도가 가장 0에 가까운 곳은 6개로

차이가 있음을 알 수 있습니다.

최적화가 쉽지 않아보이지만 둘 중 더 토픽을 잘 나타내는 것으로 최종 선택을 할 수 있겠습니다.

혼란도가 가장 낮은 토픽 17개로는 이미 전에 모델링을 실행해 보았으니,

이번에는 응집도가 가장 높은 토픽 6개로 모델링을 해보도록 하겠습니다.

num_topics = 6
passes = 5
model2 = LdaModel(corpus=corpus,id2word=dictionary,\
    passes=passes, num_topics=num_topics,\
        random_state=7)
        
model2.print_topics(num_words=10)

#LDA모형 시각화
lda_visual2= gensimvis.prepare(model2,corpus,dictionary)
pyLDAvis.display(lda_visual2)

이 둘 중에 또는 모델을 조정하여 최종적으로 토픽 수를 정할 수 있겠습니다.

 

코드 파일

kor_LDA.ipynb
0.40MB

참고자료

1. 책- 파이썬 텍스트 마이닝 완벽 가이드(위키북스)

2. https://radimrehurek.com/gensim/models/coherencemodel.html

 

Gensim: topic modelling for humans

Efficient topic modelling in Python

radimrehurek.com

 

반응형
반응형

안녕하세요.

오늘은 LDA(Latent Dirichlet Allocation)에 대해 알아보도록 하겠습니다.

LDA는 자연어처리에서 토픽 모델링을 할 때 많이 활용되는 방법입니다.

 

토픽 모델링이란?

토픽 모델링은 어떠한 문서가 있다면 그 문서의 주제가 무엇일지에 대한 분석을 가능하게 하는 방법입니다.

보통 단어의 집합으로 토픽을 표현하고 이에 대한 토픽이 무엇일지를 파악할 수 있는데,

가령, '눈' 이라는 단어가 있을 때,

'눈', '얼굴' , '시력' 등의 단어가 같이 있으면 신체 부위인 '눈'을 말하는 것인지 알 수 있고

'눈', '겨울', '흰색' 등의 단어 집합이 있으면 하늘에서 내리는 '눈'이라는 것을 알 수 있습니다.

또한 이렇게 단어들로 토픽을 뽑아 보면 각 토픽의 단어 집합을 통해 해당 문서의 주제가 무엇일 지 유추할 수 있습니다.

 

LDA(Latent Dirichlet Allocation): 잠재 디리클레 할당

처음에 언급했듯이 LDA는 토픽 모델링에서 많이 사용됩니다.

LDA는 문서 작성 시 몇 개의 토픽을 미리 정하고 문서가 작성될 때 이 토픽과 관련된 단어들을 사용한다고 가정합니다.

문서의 구성

LDA 모형의 구조는 아래와 같습니다.

출처: https://ko.wikipedia.org/wiki/잠재디리클레할당

1. α: 디리클레 분포의 매개변수(LDA 하이퍼 파라미터)

2. M: 문서의 수

3. θ: 문서의 토픽 분포(디리클레 분포를 따름)

※ 디리클레 분포: 연속확률분포 중 하나.

k 차원의 실수 벡터 중 벡터의 요소가 양수이며 모든 요소를 더한 값이 1인 경우 실수 벡터에서 각 벡터 값이 양수이고 모든 값을 더하면 1이 되는 경우에 대해 확률값이 정의되는 분포(출처:위키피디아-디리클레 분포)

예시: 문서에 토픽 3개 선정시 토픽의 비중을 [0.4, 0.4, 0.2]로 할당한다. 이 값을 다 더하면 1이 된다.

4. β: 각 토픽의 단어 분포에 관여하는 매개변수( LDA 하이퍼 파라미터)

5. Z: 문서에 있는 토픽

6. W: Z에 있는 단어들

7. N: 문서에 나타난 단어들의 빈도

 

이에 대해 간단히 설명하자면

LDA는 주어진 문서에 사용된 단어(W)들의 빈도(N)를 측정하고, 이로부터 문서의 토픽분포(θ)와 각 토픽의 단어분포를 추정합니다.

또한 LDA를 실행할 때, 토픽의 개수 k와 위에서 언급한 α, β 를 사용자가 설정해주어야 합니다.

위의 설정값들을 어떻게 설정하느냐에 따라 LDA 토픽 모델링의 성능을 높일 수 있습니다.

이때, 적절한 값을 판단하기 위해 혼란도(perplexity)와 토픽 응집도(topic coherence)를 이용합니다.

 

LDA 모형 평가

- 혼란도(perplexity): 사용자가 추정한 LDA모형이 실제 문서 집합과 비교했을 때 얼마나 유사한지 알아보는 척도입니다.

혼란도는 값이 작을수록 문서집합을 잘 반영하고 있다고 해석할 수 있습니다.

- 토픽 응집도(topic coherence): 각 토픽에 속한 단어들 중 높은 비중을 가진 단어들이 의미적으로 서로 유사한지를 나타냅니다.

토픽 응집도는 혼란도와는 반대로, 값이 클수록 좋습니다.(어떤 응집도 방법을 선택하느냐에 따라 차이는 있을 수 있습니다.)

 

성능 평가시 주의할 점

사용자가 모델링한 LDA 모형을 평가 시 가장 중요한 것은

혼란도 또는 토픽 응집도 수치에만 너무 집착하지 않는 것입니다.

LDA를 실행 후 사람의 눈으로 봤을 때 토픽과 그 단어의 구성이 자연스러운 것이 가장 좋은 모델입니다.

때문에 최종적으로 토픽 수 결정 시에는 척도 값만 보고 토픽 수를 결정하기보다,

최적값 근처의 값들을 추가로 선택 후 

그 값들에 대해 모델링을 해보고 결과들을 사용자가 본인의 눈으로 직접 비교하여 최종 값을 선택하는 것이 좋습니다.

 

참고자료

1. 파이썬 텍스트 마이닝 완벽 가이드(책)

2. 위키피디아 - 잠재 디리클레 할당

반응형
반응형

안녕하세요. 

오늘 포스팅은 전에 알아보았던 BERT의 사전학습된 모형을 사용하는 간단한 방법을 알아보도록 하겠습니다.

BERT 사전학습 모델은 허깅페이스(Hugging Face)에서 제공해서 사이트를 이용해보도록 하겠습니다.

 

1. 라이브러리 설치

anaconda prompt 또는 기타 터미널 창을 열어 transformers 라이브러리를 설치해 주세요.

CPU환경에서 사용할 것이므로 아래의 명령어를 입력해 줍니다.

pip install transformers

만약 다운로드 중 권한 오류가 있다면 관리자 권한으로 실행하시길 바랍니다.

가상환경으로 실행하고 싶은 분들은 사용할 가상환경 activate 후 설치하시면 됩니다.

 

2. transformers 파이프라인(pipeline)

transformers 라이브러리에서는 pipeline(파이프라인) 클래스를 제공하는데요,

이 클래스를 사용하면 알아서 입력값을 토크나이저를 이용해 BERT에 맞는 입력으로 변환하여 주고,

BERT 사전학습 모델에 전달하여 예측값을 반환합니다.

때문에 코드 몇 줄 만으로 간단히 사전학습 모델을 사용할 수 있습니다.

pipeline에서 지원하는 사전학습 모델 종류는 아래와 같습니다.

1. Sentiment-analysis : 감정분석
2. Text-generation : 텍스트 생성
3. NER(Named entity recognition): 개체명 인식
4. Question-answering : 기계독해
5. Fill-mask : 빈칸 예측하기
6. Summarization : 문서 요약하기
7. Translation : 번역하기

이번에 입력하는 텍스트는 영어로 입력하여야 합니다.

이제 위의 7가지 사전학습 모델 간단 사용법을 각각 알아보도록 하겠습니다.

참고로, 각 모델을 사용하며 입력한 문장 몇개들은 위키피디아에서 가져왔습니다.

2.1 감정분석

감정분석은 텍스트에 대해 긍정적인 감정을 담고 있는지 부정적인 감정을 담고 있는지 예측하는 모델입니다.

예시)
1. 이 영화는 재미있다 -> positive(긍정)
2. 이 음식은 맛없다. -> negative(부정)
사용방법: pipeline('sentiment-analysis')
from transformers import pipeline

# text classification : 감정분석
classifier= pipeline('sentiment-analysis')
sentence = "I can't wait for watching this movie!" #감성분석하고 싶은 문장 입력
result = classifier(sentence)[0]
print("입력문장: ",sentence)
print('감성분석결과: %s, 감성스코어: %0.2f'%(result['label'],result['score']))

여기서는 I can't wait for watching this movie!(이 영화를 빨리 보고 싶어!) 라는 문장을 예시로 넣어 보았습니다.

그 후 분석결과와 감성 스코어를 소숫점 2자리수까지 출력하도록 설정하였습니다.

그 결과 이 문장은 POSITIVE(긍정적)인 문장이며 점수 역시 1.00이 나왔습니다.

점수는 0~1 사이로, 점수가 1에 가까워질수록 긍정적이라고 할 수 있습니다.

 

2.2 텍스트 생성

텍스트 생성은 어느 한 텍스트를 입력 받아 그 뒤의 문장을 만들어 줍니다.

예시)
입력 문장: 나는 사과를 먹었다.
텍스트 생성: 나는 사과를 먹었다. 그래도 아직 배가 고파서 바나나를 먹었다.
사용방법: pipeline('text-generation')
# text generation : 문장 생성
text_generator = pipeline('text-generation')
sentence = "I was sitting on my bed."
result = text_generator(sentence)
print("생성된 문장: ",result[0]['generated_text'])

입력 문장으로 

"I was sitting on my bed."(나는 내 침대 위에 앉아 있었다.)를 입력 후

텍스트 생성을 하니,

I was sitting on my bed. I could see the moon and it was beautiful. I was sitting on my pillow. It was gorgeous. I looked at my bed. I was wearing my jeans at the side and the top. It was so nice

(나는 침대 위에 앉아 있었다. 나는 달을 볼 수 있었고 그것은 아름다웠다. 나는 베개 위에 앉아있었다. 정말 황홀했다. 나는 침대를 바라봤다. 나는 청바지를 입고 있었다. 너무 좋았다.)

입력된 문장에 이어서 위와 같은 문장을 출력하였습니다.

출력 결과는 실행할 때마다 매번 달라집니다.

 

2.3 개체명 인식

개체명 인식(NER: Named entity recognition)이란 입력된 텍스트 속에 사람 이름, 단체 이름 등과 같이 고유한 의미가 있는 단어를 찾아 분류하는 기술입니다.

예시)
입력 -> 영희는 이번에 애플에서 새로 출시한 아이폰을 샀다.
출력 -> 영희: 사람 이름, 애플: 회사 이름, 아이폰: 물건 이름

transformers에서 인식하는 개체는 아래와 같습니다.

[토큰 설명]
O : Outside of a named entity (NER에서 인식범위를 벗어난 개체)

B-MIS : Beginning of a miscellaneous entity right after another miscellaneous entity
(기타 개체 바로 뒤에 오는 기타 개체의 시작)

I-MIS : Miscellaneous entity(기타 개체)

B-PER : Beginning of a person’s name right after another person’s name
(사람 이름 바로 뒤에 오는 사람 이름의 시작)

I-PER :  Person’s name(사람 이름)

B-ORG : Beginning of an organisation right after another organisation
(단체 이름 바로뒤에오는 단체 이름의 시작)

I-ORG : Organisation (단체)

B-LOC : Beginning of a location right after another location(지리적 위치 바로 뒤에 오는 위치의 시작)
I-LOC : Location (지리적 위치)
사용방법: pipeline('ner')
ner = pipeline('ner')
sentence = 'BTS is a South Korean boy band formed in 2010 and debuting in 2013 under Big Hit Entertainment.'
result = ner(sentence)
print(sentence)
for i in range(len(result)):
    print("-단어: ",result[i]['word'],", 구분: ",result[i]['entity'],end=' ')

입력 문장으로

'BTS is a South Korean boy band formed in 2010 and debuting in 2013 under Big Hit Entertainment.'

(BTS는 2010년에 결성된 아이돌이며 빅히트 엔터테인트먼트에서 2013년도에 데뷔하였다.)

라는 문장을 입력하여 아래와 같은 개체명 인식 결과가 나왔습니다.

-단어:  BT , 구분:  I-ORG 

-단어:  ##S , 구분:  I-ORG 

-단어:  South , 구분:  I-MISC 

-단어:  Korean , 구분:  I-MISC 

-단어:  Big , 구분:  I-ORG 

-단어:  Hit ,  구분:  I-ORG 

-단어:  Entertainment , 구분:  I-ORG

BTS, Big Hit Entertaintment를 단체라고 구분하였습니다. South Korean은 기타로 분류하였네요.

 

2.4 기계독해

기계독해는 우리가 국어 지문을 읽고 문제를 푸는 것처럼

어떠한 문서가 있으면 그것을 입력 값으로 주고 지문과 관련한 질문을 해서 맞추는 것을 말합니다.

예시)
입력: "레몬은 신맛이 나는 과일이다."
질문: "신맛이 나는 과일은?"
답: "레몬"
사용방법: pipeline('question-answering')
# Question answering : 기계독해
question_answering = pipeline("question-answering")
context = """
Shake Shack is an American fast casual restaurant chain based in New York City. It started out as a hot dog cart inside Madison Square Park in 2001, and its popularity steadily grew.
In 2004, it received a permit to open a permanent kiosk within the park, expanding its menu from New York–style hot dogs to one with hamburgers, hot dogs, fries and its namesake milkshakes.
Since its founding, it has been one of the fastest-growing food chains, eventually becoming a public company filing for an initial public offering of stock in late 2014. The offering priced on January 29, 2015; the initial price of its shares was at $21, immediately rising by 123% to $47 on their first day of trading.
Shake Shack Inc. owns and operates over 400 locations globally.
"""
question = "How many locations Shake Shack Inc. operates?"
result = question_answering(question=question,context=context)
print("지문: ", context)
print("문제: ",question)
print("답: ", result['answer'])

지문으로 셰이크쉑에 대한 위키피디아 지문을 넣었습니다.

그 후 질문으로 "쉐이크쉑은 얼마나 많은 가게를 운영하고 있나?" 라는 질문을 했고

그 결과 "over 400(400개 이상)"이라는 답을 받았습니다.

 

2.5 빈칸 예측하기

빈칸 예측하기(fill-mask)는 문장에 마스킹 처리를 해 놓고 그 안에 들어갈 단어가 무엇일지 예측하는 모델입니다.

예시)
문장: 나는 자러 [        ]에 간다.
예측 : 나는 자러 [침대]에 간다.
사용방법: pipeline('fill-mask')

transformers에서는 해당 모델 사용 시

마스킹 하는 부분을 fill_mask객체.tokenizer.mask_token 로 설정하여 사용합니다.

# Fill-mask : 빈칸 예측하기
from pprint import pprint
fill_mask = pipeline("fill-mask")
sentence =  f"AlphaGo is a computer {fill_mask.tokenizer.mask_token} that plays the board game Go."
result = fill_mask(sentence)
print("문장: ",sentence)
pprint(result)

문제로 위키피디아에서 설명하는 알파고에 대한 문장 중 하나를 가져왔습니다.

"알파고는 보드게임 Go 를 하는 컴퓨터 <mask>이다."

라고 입력값을 주었고, 원래 문장은 "알파고는 보드게임 Go 를 하는 컴퓨터 프로그램(program)이다." 였습니다.

그 결과값으로는 빈칸에 들어갈 수 있는 여러 단어가 출력이 되었습니다.

위에서 부터 차례대로 점수가 높은 순이며,

program, game, emulator, simulator, simulation 등의 단어가 들어갈 수 있다고 예측하였습니다.

 

2.6 문서 요약하기

문서 요약(summarization)은 말 그대로 긴 문서를 몇 문장으로 요약하는 것을 말합니다.

예시)
문서: 전국이 대체로 흐린 가운데 오전 중부지방을 시작으로 눈이 내렸다. 오후서울 등 수도권과 강원 일부 지방은 최대 10㎝ 이상의 많은 눈이 예상돼 대설특보가 발효됐다. 기상청은 이날 "오늘 오전부터 강원중·남부동해안을 제외한 중부지방부터 비 또는 눈이 시작돼 오후부터 전북, 경북북부내륙, 경북남서내륙, 경남서부내륙, 밤부터 전남권북부에 비 또는 눈이 오는 곳이 있겠다"며 "수도권과 충남북부는 늦은 오후에 대부분 그치겠고, 그 밖의 지역은 밤에 대부분 그치겠다"고 밝혔다. (출처: https://n.news.naver.com/mnews/article/003/0011593636?sid=103)

요약: 새벽부터 내린 비나 눈이 점차 확대되면서 경기동부와 강원영서에는 최고 10cm 이상의 많은 눈이 쌓이겠다. 낮 동안 소강상태를 보이는 곳이 많겠으나 저녁부터 다시 강해져 모레 월요일 출근길이 빙판길로 변할 가능성이 높다. 이번 눈이나 비는 짧은 시간 강하게 내리다가 그치는 형태라 강수량보다는 적설량이 많을 것으로 보인다.
사용방법: pipeline('summarization')

min/max_length으로 최소/최대 길이를 조정할 수 있습니다.

# Summarization : 문서 요약하기
summerizer = pipeline('summarization')
article = """An apple is an edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek, and European Christian tradition.
Apples grown from seed tend to be very different from those of their parents, and the resultant fruit frequently lacks desired characteristics. Generally, apple cultivars are propagated by clonal grafting onto rootstocks. Apple trees grown without rootstocks tend to be larger and much slower to fruit after planting. Rootstocks are used to control the speed of growth and the size of the resulting tree, allowing for easier harvesting.
There are more than 7,500 known cultivars of apples. Different cultivars are bred for various tastes and uses, including cooking, eating raw, and cider production. Trees and fruit are prone to a number of fungal, bacterial, and pest problems, which can be controlled by a number of organic and non-organic means. In 2010, the fruit's genome was sequenced as part of research on disease control and selective breeding in apple production.
Worldwide production of apples in 2018 was 86 million tonnes, with China accounting for nearly half of the total."""
result = summerizer(article,max_length=150,min_length=50)
print("문서: ",article)
print("요약: ",result[0]['summary_text'])

입력 문서로 위키피디아에 '사과' 문서를 사용하였습니다.

요약으로 긴 문장을 3문장 정도로 축약한 것을 확인할 수 있습니다.

 

2.7 번역

번역(Translation)은 어떠한 나라의 언어에서 다른 나라의 언어로 통역해주는 모델을 말합니다.

예시)
한국어: 나는 사과를 좋아한다.
                      ↓
영어: I like apples.
사용방법: pipeline('translation_언어_to_언어')

transformers에서 제공하는 번역은 영어-독일어(en_to_de), 영어-루마니아어(en_to_ro) 입니다.

여기서는 영어-독일어 번역(translation_en_to_de)을 사용해 보도록 하겠습니다.

# Translation : 번역하기
translator = pipeline('translation_en_to_de')
sentences = "Bitcoin is a decentralized digital currency that can be transferred on the peer-to-peer bitcoin network."
result = translator(sentences, max_length=50)
print("영어: ",sentences)
print("독어: ",result[0]['translation_text'])

영어 입력문장은 위키피디아 비트코인 문서에서 가져온 문장을 사용하였습니다.

출력 값으로 독일어 번역이 된 문장을 반환합니다.

 

참고자료

https://huggingface.co/docs/transformers/task_summary#translation

 

Summary of the tasks

>>> from transformers import pipeline >>> text_generator = pipeline("text-generation") >>> print(text_generator("As far as I am concerned, I will", max_length=50, do_sample=False)) [{'generated_text': 'As far as I am concerned, I will be the first to admit

huggingface.co

마무리

이번에 간단하게 사전학습된 BERT모형 사용법을 알아보았습니다.

기본 제공이 영어라 한국어 적용도 해보고 싶어서

다음 포스팅에서는 한국어로 사용할 수 있는 방법을 알려드리도록 하겠습니다.

반응형
반응형

안녕하세요.

python을 하시는 분들이라면 pandas를 자주 사용하실텐데요,

이 때 , 만들어 둔 csv파일을 to_csv로 저장을 할 때

인코딩 설정을 'utf-8'로 하는 경우가 있습니다.

IDE로 작업 할 땐 아래처럼 한글이 잘 보였는데

실제 저장된 파일을 열어보면,

한글이 깨져 있는 것을 확인할 수 있습니다.

이렇게 되면 파일만 있을 때 어떤 정보가 있는지 확인이 어렵습니다.

그럴 때는 pandas로 csv를 저장 시 인코딩을

utf-8 대신 'utf-8-sig'를 사용하면 한글깨짐을 방지할 수 있습니다!

이렇게 'utf-8-sig' 를 사용하면 저장한 파일을 열어도 한글이 깨지지 않고 잘 보입니다 :)

 

반응형
반응형
사전학습모델이란?

사전학습모델(pre-training model)은 어떠한 새로운 문제를 해결하려 모델을 만들어 학습시킬 때,

 기존의 다른 문제를 해결하는 데 사용한 모델의 가중치들을  활용하여 구성하는 모델을 말합니다.

예를 들어,

전에 감성 분석 모델을 미리 만들어 놓았었고 이번에는 텍스트 유사도 예측 모델을 만든다고 할 때,

미리 만들어 놓은 감정 분석 문제 모델의 가중치를 텍스트 유사도 예측 모델의 가중치로 활용하는 것이라 할 수 있습니다.

즉, 감성 분석 문제를 학습하면서 얻은 정보를 유사도 문제를 학습하는 데 활용하는 방식이라고 할 수 있습니다.

이때, 감정 분석 문제는 사전 학습 문제(pre-train-ask)가 되고,

텍스트 유사도 문제는 하위 문제(downstream task)가 됩니다. 

자주 사용하는 사전학습 문제: 언어 모델

위에서 사전학습 모델과 그 예를 알아보았는데

실제 연구에서는 보통 사전 학습 문제로 '언어 모델(language model)'을 사용합니다.

언어 모델(language model)이란?

언어모델은 문장 또는 단어 나열에 확률을 부여하는 모델입니다.

간단히 말해 특정 단어가 있을 때 그 다음 단어 또는 다른 위치에 있는 단어가 어떤 단어일지를  예측하는 모델입니다.

예를 들어,
"나는 추워서 롱패딩을 입었다." 이 문장이 있을 때, 마지막 부분인 "입었다."를 모델이 예측하며 학습합니다.

또한 "나는 너무 졸려서 잔다." 와 "나는 너무 졸려서 일어난다." 의 두 문장이 있을 때,

언어 모델은 더 자연스러운 문장인 "나는 너무 졸려서 잔다." 라는 문장에 더 높은 확률을 할당합니다.

여기서 자연스럽다는 의미는 일반적으로 더 많이 사용된다는 의미로,

이렇듯 언어 모델은 언어에 대한 이해를 높여주는 모델이라고 할 수 있습니다.

또한 정답 라벨이 필요 없는 비지도 학습이므로 지도 학습에 비해 전처리 시간이 줄어듭니다.

 

BERT란?

BERT(Bidirectional Encoder Representation from Transformers)는

2018년도에 나온

<<BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding>>

라는 논문에서 제안된 사전학습모델입니다.

BERT(버트)에서 활용하는 사전 학습 문제는 위에서 언급한 언어 모델(language model)이며,

트랜스포머에서 인코더 부분만 사용한 모형입니다.

인코더의 특징으로 양방향(bidirectional) 셀프 어텐션을 구현하고 있다는 것이 있습니다.

이는 다른 사전학습 모델(GPT, ELMo)등과 비교했을 때 확연히 다른 차이점입니다.

출처:&nbsp;https://arxiv.org/pdf/1810.04805.pdf

BERT의 학습

BERT 의 학습으로,

1. 사전학습

2. 미세조정학습

이렇게 두 단계가 있습니다.

여기서 사전학습은 비지도학습이고, 미세조정학습은 해결해야 하는 문제에 대한 지도학습입니다.

 

BERT의 사전학습

BERT는 두 문제를 사전 학습합니다.

두 문제는 아래와 같습니다.

1.1 마스크 언어 모델

- 마스크 언어 모델: 주어진 문장에서 일부 단어를 마스킹(가림) 처리하여 가려진 단어가 무엇인지 예측하는 학습
여기서, BERT는 마스킹된 앞 뒤 단어 (양 방향)를 모두 사용해서 가려진 단어를 예측한다.

성능 향상을 위해 마스킹 할 단어의 80% 는 [MASK]라는 토큰을 사용하고,
10%는 다른 단어로 바꾸고, 마지막 10%는 단어 그대로 놔둔다.
예) 원래 문장: 분석은 전처리 과정이 매우 중요하다.
      마스킹 후 문장: 분석은 [MASK] 과정이 오늘 중요하다.

1.2 다음 문장 예측(next sentence prediction)

- 다음 문장 예측: 두 개의 주어진 문장에서 이 두 문장이 이어진 문장인지 아닌지를 분류하는 학습
이를 통해 문장 간의 관계를 학습할 수 있다.
데이터 셋 구성 시 50%는 이어진 문장, 나머지 50%는 이어지지 않은 문장으로 구성한다.
앞 문장에는 [CLS]라는 토큰을 넣고, 두번째 문장 앞과 맨 끝에는 [SEP] 토큰을 넣어 문장을 구분할 수 있도록 처리한다.
예) [CLS] 분석은 [MASK] 과정이 [MASK] 중요하다. [SEP] 그래서 [MASK] 시간이 많이 걸린다.[SEP] 
위의 예시에서 모델은 가려진 단어들과 두 문장이 이어졌는지 아닌지를 예측한다.

 

BERT의 미세조정학습

미세조정학습은 사전학습으로 BERT의 언어에 대한 이해가 학습되고,

이를 통해  최종적으로 해결하여야 하는 하위문제(예: 문서 분류, 유사도 측정 등)를 풀기 위한 학습을 말합니다.

여러 문제와 관련한 미세조정-출처: https://arxiv.org/pdf/1810.04805.pdf

미세조정 학습을 하고 나면,

사전학습으로 만들어진 가중치들이 하위 문제에 맞게 세밀하게 조정되어 최종적인 예측 값을 반환합니다.

 

참고자료

1. 텐서플로2와 머신러닝으로 시작하는 자연어처리(위키북스)

2. 파이썬 텍스트 마이닝 완벽 가이드(위키북스)

3. BERT논문 - https://arxiv.org/pdf/1810.04805.pdf

마무리

이번에는 간단하게 사전학습 모델이 무엇인지, BERT가 무엇인지 알아보았습니다.

BERT를 개인이 직접 사전학습하려면 많은 비용과 시간이 들어갈 것입니다.

그래도 개인이 BERT를 사용할 수 있는 방법이 있습니다.

바로 사전학습된 모형을 무료로 제공하는 웹사이트들을 활용하는 것입니다.

다음 포스팅에서는 허깅페이스(Hugging Face)에서

미리 사전학습된 BERT를 사용하는 방법을 같이 알아보도록 하겠습니다.  

반응형
반응형

Selenium을 사용할 때 드라이버를 다운 받아야 하는데,

크롬 브라우저 사용 시 드라이버를 현재 본인의 크롬 브라우저 버전에 맞춰 다운을 받아줘야 합니다.

예를 들어 한 달 전에 브라우저 1.0 버전을 쓰고 있으면 드라이버도 1.0을 써야 하고,

이후 브라우저를 업데이트 했다면 기존의 드라이버도 역시 해당 버전을 다시 설치해 주어야 합니다.

 

이렇게 매번 selenium 사용시마다 다운받고 설치하는 작업이 번거로운데,

webdriver_manager을 사용하면 드라이버를 직접 다운받지 않고도 자동 설치되며

selenium 이 오류 없이 실행됩니다.

 

라이브러리 설치
pip install webdriver-manager

 

코드
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

# 크롬 드라이버 설치
driver = webdriver.Chrome(ChromeDriverManager().install())

#페이지 불러오기
driver.get('사이트주소')

+ 추가(24.01.27)

요즘은 최신버전으로 크롬업데이트후 selenium을 설치해주시면 드라이버 설치없이도 바로 실행가능합니다.

꼭 크롬 브라우저가 최신버전으로 업데이트되어있는지 확인해주세요.

이미 selenium을 설치한 경우, 최신버전 크롬으로 업데이트후

pip uninstall selenium 으로 기존 셀레니움 삭제 후

재설치 해주시면 실행 됩니다.

from selenium import webdriver

# 크롬 드라이버 설치
driver = webdriver.Chrome()

#페이지 불러오기
driver.get('사이트주소')

+ 위의 방법 사용 중 오류가 나타날 경우

seleniumbase 설치 
pip install seleniumbase
driver 설정
from seleniumbase import Driver
driver = Driver(browser="chrome")

driver.get('사이트주소')

 

유용하게 사용하시길 바랍니다.

반응형
반응형

안녕하세요!

오늘은 Pandas의 apply 메서드를 사용하는 방법을 알아보도록 하겠습니다.

 

종종 pandas로 csv 파일을 열어 dataframe을 만들 때, 

각 행을 계산한다던가, 열을 계산하여야 할 때가 있습니다.

이때 pandas 의 apply 메서드를 사용하면 만들어 둔 함수를 간편하게 적용하여 계산이 가능합니다.

 

데이터 준비

데이터는 kaggle의 Lemonade-Orange-stand를 사용해 보겠습니다.

https://www.kaggle.com/datasets/adisak/lemonade-stand

 

Lemonade-Orange-stand

Lamonade and Orange Stand sales

www.kaggle.com

이 데이터는 각 날짜의 레몬, 오렌지 에이드 판매량을 보여주는 데이터셋입니다.

링크를 들어가서 Lemonade2016-2.csv 파일을 다운받아 줍니다.

그 후 csv파일을 아래와 같이 열어 줍니다.

import pandas as pd
df = pd.read_csv('Lemonade2016-2.csv')
df


각 컬럼의 의미는 다음과 같습니다.

Date: 날짜

Location: 판매장소(공원/해변가)

Lemon: 레몬에이드 판매량(잔)

Orange: 오렌지에이드 판매량(잔)

Temperature: 기온(화씨/ºF)

Leaflets: 배포한 전단지 수

Price: 가격($)

 

Series에서 apply 적용하기 - 1개의 인자를 전달받는 함수
현재 df에 있는 temperature은 화씨온도로 한국에서 쓰는 섭씨온도랑 단위가 다릅니다.
때문에 온도를 이해하기 쉽게 섭씨 온도로 바꿔주는 작업을 해보도록 하겠습니다.
 
화씨온도에서 섭씨온도로 변환하는 식은 아래와 같습니다.

°C = (°F−32)×5/9

이것을 'to_C'라는 함수로 만들어 보겠습니다.
#화씨->섭씨 함수
# (temperature - 32) * 5 / 9
def to_C(x):
    C = (x - 32) * 5 / 9
    # 소수 셋째자리에서 반올림
    C = round(C,2)
    return C

그리고 df에서 따로 날짜컬럼만 빼어서 apply 함수 적용 후 새로운 df열에 할당해 주도록 하겠습니다.

# 기온(temperature)을 섭씨(ºC)로 변환
temp = df['Temperature']
# apply 함수 적용 후 새로운 열에 섭씨온도 추가해 주기
df['temp_C'] = temp.apply(to_C)
df
 
오른쪽 맨 끝열에 섭씨 온도가 잘 추가되었습니다.
 
2개의 인자를 전달받는 함수 - 25센트짜리 레몬에이드 판매액을 구하기
이번에는 각 날짜의 레몬에이드 판매액이 얼마인지 apply를 사용해 구해보도록 하겠습니다.
레몬에이드 판매액은
 
레몬에이드 판매 수 x 가격
 
으로 구할 수 있습니다.
이번에는 레몬에이드가 25센트일때의 그날의 판매액을 구하는 것이므로
먼저 레몬에이드가 25센트인 날만 필터링하여줍니다.
# price가 0.25인것만 필터링
cent_25 = df[df['Price'] == 0.25]
cent_25

 이렇게 25센트인 날만 추출이 완료되었습니다.

 

 
그 후, 판매액을 구하는 함수를 만들어 apply로 적용해 줍니다.
 
apply 적용 시 Lemon열에서 적용하여 줍니다. price는 0.25로 모든 열이 같으므로
price 인자를 전달할 때 price=0.25로 고정하여 줍니다.
#판매액 을 구하는 함수
def lemon_money(x, price):
    total = x * price
    return total
cent_25['Lemon'].apply(lemon_money,price=0.25)
이렇게 판매액 계산이 완료되었습니다.
 
Dataframe에서 apply 적용하기 - 3개의 인자를 입력받아 계산하는 경우
이번에는 레몬 에이드와 오렌지 에이드 판매량을 합쳐 각 날짜의 총 판매액을 구해보도록 하겠습니다.
이것을 함수로 작성한다면 일반적인 경우는 아래와 같이 작성할 것 입니다.
 
(레몬에이드 판매량 +오렌지에이드 판매량) *가격
def total(x,y,price):
    total_money = (x+y)*price
    return total_money
하지만 dataframe에 apply를 적용할 때는 행 단위 또는 열 단위로만 값을 입력받기 때문에,
위의 함수식을 한개의 인자를 받는 함수로 바꾸어야 합니다.
그 후 이 함수식 안에서 3개의 인자를 생성하는 방향으로 함수를 수정하겠습니다.
 
이 때, df에서 사용하는 값이 각 행의 'Lemon', 'Orange', 'Price' 컬럼 이므로 
이를 각각 함수 내에서 x,y,price라는 변수 생성후 열 번호로 할당을 해주도록 하겠습니다.
 
각 컬럼의 위치와 인덱스를 아래와 같이 확인하여 줍니다.
#컬럼확인
df.columns​

#컬럼 번호 확인
for itr,i in enumerate(df.columns):
    print(itr,' : ',i)
그 후 함수를 한 개의 인자값을 받는 함수로 수정하여 줍니다.
# 1개의 인자값을 가지는 함수로 변경
# x=레몬에이드,y=오렌지에이드,price=가격 각각 열 위치로 변수 할당
def total(col):
    x = col[2] #Lemon
    y = col[3] #Orange
    price = col[6] #Price
    total_money = (x+y)*price
    return total_money
마지막으로, apply를 사용하여 해당 함수를 적용하여 줍니다.
각 열을 인자값으로 사용하므로 axis=1로 설정해 줍니다.(axis=0은 행방향)
#df에 적용하여 리턴값 새 열에 할당
# 열 기준이므로 axis = 1
df['total'] = df.apply(total,axis=1)
df​
이렇게 total 열에 총 판매액 계산이 잘 되었습니다.

 

전체 코드
import pandas as pd

df = pd.read_csv('Lemonade2016-2.csv')

# 기온(temperature)을 섭씨(ºC)로 변환
temp = df['Temperature']

#화씨->섭씨 함수
# (temperature - 32) * 5 / 9
def to_C(x):
    C = (x - 32) * 5 / 9
    # 소수 셋째자리에서 반올림
    C = round(C,2)
    return C
    
# apply 함수 적용 후 새로운 열에 섭씨온도 추가해 주기
df['temp_C'] = temp.apply(to_C)

# price가 0.25인것만 필터링
cent_25 = df[df['Price'] == 0.25]

#판매액 을 구하는 함수
def lemon_money(x, price):
    total = x * price
    return total
cent_25['Lemon'].apply(lemon_money,price=0.25)

#컬럼확인
df.columns
#컬럼 번호 확인
for itr,i in enumerate(df.columns):
    print(itr,' : ',i)

# 1개의 인자값을 가지는 함수로 변경
# x=레몬에이드,y=오렌지에이드,price=가격 각각 열 위치로 변수 할당
def total(col):
    x = col[2] #Lemon
    y = col[3] #Orange
    price = col[6] #Price
    total_money = (x+y)*price
    return total_money
    
#df에 적용하여 리턴값 새 열에 할당
# 열 기준이므로 axis = 1
df['total'] = df.apply(total,axis=1)
df
코드파일

apply_practice.ipynb
0.06MB

 

참고자료

Do it! 데이터 분석을 위한 판다스 입문

 

마무리

apply는 활용도가 높은 메서드 입니다. 유용히 사용하셨으면 좋겠습니다 ㅎㅎ

 

+ Blogspot 블로그도 개설하였습니다!

종종 방문해 주시면 좋겠습니다 ㅎㅎ

https://wonhwa1.blogspot.com/2022/10/python-pandas-apply.html

 

[python] pandas Apply를 사용하여 함수를 한번에 적용하기

Apply 종종 pandas로 csv 파일을 열어 dataframe을 만들 때,  각 행을 계산한다던가, 열을 계산하여야 할 때가 있습니다. 이때 pandas 의 apply 메서드를 사용하면 만들어 둔 함수를 간편하게 적용하여 계산

wonhwa1.blogspot.com

 

반응형
반응형

안녕하세요.

저번 포스팅에 이어서 pandas를 활용하여 날짜&시간 데이터를 다루는 방법 2편 시작하도록 하겠습니다!

 

데이터 준비

이번에 사용할 데이터는 국가 별 기대수명 데이터 입니다!

15개의 각 나라에 대한 년도별 기대수명이 있는 데이터 입니다.

Kaggle에서 다운받을 수 있으며 아래의 링크에서 찾을 수 있습니다.

https://www.kaggle.com/datasets/brendan45774/countries-life-expectancy

 

Countries Life Expectancy

Countries Life Expectancy

www.kaggle.com

Download 버튼을 눌러서 다운받으실 수 있습니다 ㅎㅎ

 

CSV 파일 불러오기 및 데이터 확인
import pandas as pd
df = pd.read_csv("Life expectancy.csv")
df

데이터를 확인해 보면 3253행  x3열 이며 각 컬럼은 나라(Entity), 년도(Year), 기대수명(Life expectancy)을 의미합니다.

여기서 시간데이터인 Year 컬럼을 to_datetime으로 형변환을 해 주도록 하겠습니다.

 

날짜형 데이터로 변환

저번 1편에서 확인했듯이 pd.to_datetime를 사용하여 형변환을 해주고 데이터 타입을 확인하여 보면 아래와 같습니다.

# year을 데이터형으로 변환
df['Year'] = pd.to_datetime(df['Year'],format = '%Y')
df.dtypes

의도했던 대로 Year 컬럼이 datetime형으로 바뀌었습니다.

데이터도 다시 확인하여 보면 날짜형으로 바뀌었음을 알 수 있습니다.

 

날짜, 시간데이터의 증감 - timedelta

이 시간데이터를 가지고 날짜, 시간데이터의 증감을 해 보도록 하겠습니다.

datetime의 timedelta를 이용하면 날짜별, 시간별로 데이터를 더할 수 있습니다.

# 일자 더하기
날짜데이터 + datetime.timedelta(days = 더할 일수)

# 시간 더하기
날짜데이터 + datetime.timedelta(hours = 더할 시간)

# 분 더하기
날짜데이터 + datetime.timedelta(minutes = 더할 분)

# 초 더하기
날짜데이터 + datetime.timedelta(seconds = 더할 초)

아래 예제에서는 각각 1일, 1시간, 1분, 1초를 Year 열에 더해 보았습니다.

import datetime
# 시간 더하기
#일 
addDay = df['Year']+ datetime.timedelta(days=1)
#시
addHour = df['Year']+ datetime.timedelta(hours=1)
#분
addMinute = df['Year']+ datetime.timedelta(minutes=1)
#초
addSecond = df['Year']+ datetime.timedelta(seconds=1)

각각 데이터가 잘 더해진 것을 확인할 수 있습니다.

Pivot_table을 사용하여 행, 열 바꾸기

이 데이터를 보면 나라별로 데이터가 나누어져 있습니다. 

이 데이터를 Year을 인덱스로 하여 행으로 바꿔주고 나라를 컬럼으로, 기대수명을 값으로 하여 

데이터 프레임을 만들어 보도록 하겠습니다.

이 때 pivot_table을 사용하여 값을 바꿀 수 있습니다.

pivot_table에 대한 자세한 내용은 전에 포스팅을 참고해 주세요.

https://wonhwa.tistory.com/27?category=996516 

 

[python] pandas(판다스) - groupby, pivot_table, melt

Pandas는 데이터 분석을 할 때 필수적으로 사용하는 파이썬 라이브러리입니다. 오늘은 유용하게 쓰일 수 있는 판다스의 메소드 몇 가지를 간단히 알아보도록 하겠습니다. Groupby 그룹바이 pandas.grou

wonhwa.tistory.com

# 피벗으로 행렬 전환
# index = Year
# columns = Entity
# values = Life expectancy
df_pivot = df.pivot_table(
                index='Year',
                columns='Entity',
                values='Life expectancy')
df_pivot

이렇게 원하는 모양의 데이터프레임이 만들어졌습니다 :)

이제 이 csv 파일을 저장 후 다음 예제는 이 파일을 사용해 보도록 하겠습니다.

# 피벗한 테이블 csv 저장
df_pivot.to_csv('LifeExp_pivot.csv')

df_pivot = pd.read_csv('LifeExp_pivot.csv')

 

날짜 데이터를 분류하기

이 데이터는 1800년부터 2016년도까지의 총 217년의 데이터가 있는데 

각 세기별로 나누어 데이터를 확인해 보도록 하겠습니다.

1세기 = 100년 이며

이데이터는 18C~21C까지의 데이터 이므로 컬럼을 하나 만들어 각 세기를 입력해 주도록 하겠습니다.

년도를 세기별로 변환하는 방법으로

1. 함수를 만들기

2. apply함수를 이용한 계산 및 Categorical을 이용하여 범주형으로 입력

이렇게 2가지를 거쳐 쉽게 분류할 수 있습니다.

먼저 아래와 같이 함수를 만들어 각 년도별 해당 세기를 return 하는 함수를 만들어 줍니다.

예를 들어 19C는 1801년~1900년 까지 입니다.

if , elif, else 를 이용하여 만들 수 있습니다.

# 세기별로 나누기
# 18,19,20,21세기
#예) 19세기: 1801-01-01 ~ 1900-12-31

# 년도를 세기별로 변환하는 함수
def to_century(year_num):
    century = '21C'
    if year_num == 1800:
        century = '18C'
    elif 1801 <= year_num <= 1900:
        century = '19C'
    elif 1901 <= year_num <= 2000:
        century = '20C'
    return century

그 뒤 Year을 기준으로 세기가 정해지기 때문에 Year컬럼을 datetime형으로 바꿔준 후,

dt를 사용하여 year에 접근하여 그 값에대해 apply로 위에서 만든 to_century 함수를 적용해 줍니다.

그 값은 'Century'라는 컬럼에 새로 할당해 주면 완성됩니다.

#Year을 datetime64[ns]형변환 하기
df_pivot['Year'] = pd.to_datetime(df_pivot['Year'],format='%Y-%m-%d')
#세기별로 변환하기
df_pivot['Century'] = pd.Categorical(
                        df_pivot['Year'].dt.year.apply(to_century),
                        categories=['18C','19C','20C','21C'])
df_pivot

맨 끝에 Century 열이 추가 된 것을 확인할 수 있습니다.

 

시각화

이제 이것을 가지고 세기별 국가들의 기대수명을 확인해 보도록 하겠습니다.

국가는 Austrailia(호주), Brazil(브라질), Canada(캐나다), China(중국), France(프랑스), Germany(독일), India(인도), Italy(이탈리아), Japan(일본), Mexico(멕시코), Russia(러시아), Spain(스페인), Switzerland(스위스), United Kingdom(영국), United States(미국) 이렇게 15개국이 있습니다.

그리고 데이터에서 세기별로 데이터를 나누고 그 데이터를 시각화해주도록 하겠습니다.

데이터는 100년의 데이터가 다 있는 19C, 20C만 해보도록 하겠습니다.

matplotlib을 사용하여 그래프를 그리고, 국가 수 가 많으므로 범례를 추가해 주고 색도 각자 다른 색으로 추가해 주겠습니다.

matplotlib에서 제공하는 컬러맵은 아래의 링크에서 확인이 가능합니다.

https://matplotlib.org/stable/tutorials/colors/colormaps.html

 

Choosing Colormaps in Matplotlib — Matplotlib 3.6.0 documentation

Note Click here to download the full example code Choosing Colormaps in Matplotlib Matplotlib has a number of built-in colormaps accessible via matplotlib.colormaps. There are also external libraries that have many extra colormaps, which can be viewed in t

matplotlib.org

import matplotlib.pyplot as plt
import numpy as np
#19C 수명 변화 시각화
Century19 = df_pivot[df_pivot['Century'] == '19C']

fig1 = plt.figure(figsize=(15,15))
ax1 = fig1.add_subplot(111)
ax1.plot(Century19['Year'], Century19.iloc[:,1:16])

colormap = plt.cm.tab20b #컬러맵  
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]

for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])

plt.legend(Century19.columns[1:16])
plt.show()

이 각 나라별로 수명 변동이 있는데 그 중에서 러시아의 수명이 눈에 띕니다.

1848년정도에 기대수명이 18세 정도까지 떨어졌는데 

이때 왜 그런지 찾아보니

1848때 헝가리 혁명이 있었고, 그 때 러시아가 많은 사람을 파병했다고 합니다. 

이렇게 기대수명이 급감한 년도를 살펴보면 역사적인 사건들과 관련있는 것을 확인할 수 있습니다.

이번에는 20C의 기대수명을 시각화 해보도록 하겠습니다.

#20C 수명 변화 시각화
Century20 = df_pivot[df_pivot['Century'] == '20C']

fig2 = plt.figure(figsize=(15,15))
ax2 = fig2.add_subplot(111)
ax2.plot(Century20['Year'], Century20.iloc[:,1:16])

colormap = plt.cm.tab20b #컬러맵  
colors = [colormap(i) for i in np.linspace(0, 1,len(ax2.lines))]

for i,j in enumerate(ax2.lines):
    j.set_color(colors[i])

plt.legend(Century20.columns[1:16])
plt.show()

20세기는 1,2차 세계대전이 있었던 만큼 그 시기에 대부분 국가의 기대수명이 낮음을 확인할 수 있습니다.

1914~1918년도에는 제 1차 세계대전이, 1939 ~ 1945년 까지는 2차 세계대전이 있었고 그 시기 기대수명이 확 낮아졌음을 확인할 수 있습니다.

여기서 특이한 점은 인도는 특히 1918년도에 기대수명이 8세정도까지 되지않아

한 번 알아보았는데 이시기에 인도가 스페인독감으로 가장 많은 사상자를 내었다고 합니다. 1천7백만명의 사람이 사망했다고 합니다. 이시기에 다른 국가들로 독감으로 인해 많은 사망자가 나왔음을 확인할 수 있습니다.

 

전체 코드

TimeSeriesData2.ipynb
0.51MB

참고자료

1. Do it 데이터 분석을 위한 판다스 입문

2. 데이터 전처리 대전

 

마무리

이번에는 기대수명을 가지고 시간데이터 증감 하는 방법 및 분류 하는 방법도 알아보고

간단한 분석도 해보았는데 저도 하면서 재밌었네요ㅎㅎ

이렇게 역사 공부도 하고 기억에도 잘 남을 것 같습니다.

그리고 다음에 좋은 시계열데이터 예제가 있다면 관련하여 포스팅 하도록 하겠습니다.

반응형

+ Recent posts