반응형

안녕하세요!

데이터 분석을 하다보면

특히 folium으로 위치를 시각화 할 때는 숫자로 된 위경도 값이 필요한데

데이터 파일 자체에 주소만 나와있고 위경도 값이 누락되어 있는 경우가 발생합니다.

그 때 위경도 값을 구하는 방법을 알아보도록 하겠습니다ㅎㅎ

 

step1. 데이터 준비

오늘 예제로 사용할 데이터는 공공데이터의 인천 중구 커피숍 파일입니다.

아래의 링크에서 csv파일을 다운받아 주세요:)

다른 파일이 있으시다면 그 파일을 사용하셔도 무방합니다.

https://www.data.go.kr/data/15086876/fileData.do

 

인천광역시 중구_카페 및 커피숍 현황_20210805

인천광역시 중구 관내에 위치한 카페 및 커피숍 현황에 대한 데이터 입니다.<br/><br/>파일명 인천광역시_중구_카페 및 커피숍 현황<br/>파일내용 사업장명, 소재지지번주소, 도로명주소 등<br/>

www.data.go.kr

 

step2. 데이터 확인
# csv파일 불러오기
csv = pd.read_csv('incheon_coffeeshop_20210805.csv',encoding='cp949')
print(csv.head())

출력:

전에 다운받은 데이터는 위와 같은 정보를 포함하고 있음을 알 수 있습니다.

위경도 값을 찾기 전에 위의 데이터에서 도로명 주소만 따로 추출해 보도록 하겠습니다.

# 데이터프레임 주소값 추출
address= csv['소재지도로명주소']
print(address.head())

출력:

주소를 보면 맨 뒤 에 '1층'과 같은 상세주소도 포함됨을 알 수 있습니다.

위경도 값에는 층수가 포함이 되지 않고, 주소를 위경도 변환시 오류가 날 수 있어 필요한 주소만 남겨주고 나머지는 지워주는 작업을 진행하겠습니다.

 

step3. 필요한 주소만 남겨놓기
# 주소 데이터 깔끔하게 다듬기
for i in range(len(address)):
    a = address[i].split(' ')
    address[i] = " ".join(a[0:4])
print(address)

출력:

사진과 같이 필요한 정보만 담아졌음을 확인할 수 있습니다.

step4. 위경도 변환하기

그럼 이제 위 주소를 가지고 위경도 값으로 바꿔주겠습니다.

이 작업을 진행하려면 먼저 geopy라는 라이브러리를 import 해주어야 하는데요,

아래와 같이 명령창에 pip 명령어를입력해서 다운받아 주세요.

pip install geopy

그 후 아래와 같이 함수를 작성해줍니다.

####### 도로명주소 위도 경도 값으로 바꿔주기 ########
from geopy.geocoders import Nominatim
geo_local = Nominatim(user_agent='South Korea')

# 위도, 경도 반환하는 함수
def geocoding(address):
    try:
        geo = geo_local.geocode(address)
        x_y = [geo.latitude, geo.longitude]
        return x_y

    except:
        return [0,0]

위의 함수는 geocoding함수 안에 주소를 넣어주면 그 주소에 맞는 위도, 경도를

리스트로 만들어 [위도, 경도]로 반환해주는 함수입니다.

주소가 올바르지 않은 형식인 경우에는 [0,0]을 반환합니다.

이제 이 함수를 이용하여 커피숍의 위경도 값을 추출해 주도록 하겠습니다.

#####주소를 위,경도 값으로 변환하기 #####
latitude = []
longitude =[]

for i in address:
    latitude.append(geocoding(i)[0])
    longitude.append(geocoding(i)[1])

 그 후 데이터프레임으로 만들어 한눈에 보이도록 해 줍니다.

#####Dataframe만들기######
address_df = pd.DataFrame({'카페이름': csv['사업장명'],'상세주소':csv['소재지도로명주소'],'주소':address,'위도':latitude,'경도':longitude})

#df저장
address_df.to_csv('jungu_incheon_coffeeshop.csv')

이렇게 주소값만으로 위경도 값을 찾을 수 있습니다 :)

 

전체 코드
import pandas as pd
# csv파일 불러오기
csv = pd.read_csv('incheon_coffeeshop_20210805.csv',encoding='cp949')
print(csv.head())

# 데이터프레임 주소값 추출
address= csv['소재지도로명주소']
print(address.head())


# 주소 데이터 깔끔하게 다듬기
for i in range(len(address)):
    a = address[i].split(' ')
    address[i] = " ".join(a[0:4])
print(address)

####### 도로명주소 위도 경도 값으로 바꿔주기 ########
from geopy.geocoders import Nominatim
geo_local = Nominatim(user_agent='South Korea')

# 위도, 경도 반환하는 함수
def geocoding(address):
    try:
        geo = geo_local.geocode(address)
        x_y = [geo.latitude, geo.longitude]
        return x_y

    except:
        return [0,0]




#####주소를 위,경도 값으로 변환하기 #####
latitude = []
longitude =[]

for i in address:
    latitude.append(geocoding(i)[0])
    longitude.append(geocoding(i)[1])

#####Dataframe만들기######
address_df = pd.DataFrame({'카페이름': csv['사업장명'],'상세주소':csv['소재지도로명주소'],'주소':address,'위도':latitude,'경도':longitude})

#df저장
address_df.to_csv('jungu_incheon_coffeeshop.csv')

 

마무리

오늘은 주소정보만 있을때 위치 정보로 바꾸어 주는 방법을 알아보았는데요

필요시 활용해 주시길 바랍니다. ㅎㅎ

그리고 코드 관련 질문이나 기타 의견이 있다면 댓글로 남겨주세요 :)

 

++ 22/08/04 예외처리 추가

++ 관련한 최신 포스팅은 아래에서 확인 가능합니다.

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

 

[python] geopy를 사용하여 주소를 위,경도 값으로 바꾸기 & 위,경도 값을 주소로 바꾸기

geopy란? geopy는 파이썬 라이브러리로,  주소를 위,경도 숫자 값으로 바꿔 주거나(지오코딩), 반대로 위,경도 값을 사람이 읽을 수 있는 주소로 바꿔줍니다. (이를 역 지오코딩이라 합니다.) 예를

wonhwa1.blogspot.com

 

반응형
반응형

안녕하세요! 오늘은 텍스트 군집분석을 진행해보고자 합니다.

군집분석은 여러 문서들이 있을 때 유사한 텍스트끼리 그룹화하는 분석을 말합니다.

그중에서도 오늘은 분할 군집분석을 진행해 보겠습니다.

분할 군집 분석은 데이터를 k개의 그룹으로 나누어 주는 것을 말하는데 k개는 분석하는 사람에 따라 지정되는 숫자입니다. 연구자가 주관적으로 데이터 내에서 2개의 그룹으로 나누거나 3개의 그룹으로 나누어 겠다라고 결정하면 그 그룹 숫자에 따라 데이터들이 군집화 됩니다.

K-평균 군집 분석(K-means)

K-means (K-평균 군집 분석) 알고리즘은 아래의 사진으로쉽게 이해가 가능합니다.

위의 사진을 만들어 준비해 보았는데 이해가 잘 가시나요? ㅎㅎ

이제는 군집분석을 파이썬으로 구현하여 보겠습니다.

우선 데이터를 준비해 주어야 하는데요

저는 네이버 api를 이용해 뉴스 제목, 요약, 링크 등을 크롤링 하여 준비해 보았습니다.

검색어는 '크리스마스' , '쇼미더머니' , 'SK하이닉스' 이렇게 3개의 키워드로 검색된 내용을 데이터프레임으로 만들었습니다.

각각 15기사씩 총 45개의 기사가 있습니다.

데이터 파일 준비

clustering_ex.csv
0.02MB

필요한 모듈 설치

sklearn 설치

pip install sklearn

c_konlpy 설치(커스텀 할 수 있는 형태소분석기, 사전에 konlpy설치 후 ckonlpy설치)

git clone https://github.com/lovit/customized_konlpy.git

pip install customized_konlpy

pyclustering 설치

pip install pyclustering
코드
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.cluster import KMeans
from pyclustering.cluster import kmedoids
from ckonlpy.tag import Twitter
twitter = Twitter()

#데이터 불러오기
df = pd.read_csv('clustering_ex.csv')
print(df.head())

출력:

준비한 데이터셋을 보면 요약 부분에 <b>태그 등이 남아 있어 제거 한 후 분석을 진행해 보도록 하겠습니다.

# 텍스트 전처리
import re
desc = df['요약']
for i in range(len(desc)):
    desc[i] = re.sub('(<b>|</b>|&quot;)','',desc[i])
print(desc)

출력:

위와 같이 <b> 태그가 깔끔하게 없어진 것을 확인해 볼 수 있습니다.

이번 군집 분석에는 요약부분을 사용하여 분석해보도록 하겠습니다.

각 텍스트의 형태소 분석을 ckonlpy로 진행해줍니다. ckonlpy에서 검색키워드였던 크리스마스, 쇼미더머니, sk하이닉스를 명사로 추가해 줍니다. 다른 명사를 추가하고 싶다면 [] 안에 추가하면 됩니다.

분석 후 명사가 추출된 문장을 띄어쓰기로 구분하여 기사당 한 문장으로 만들어 줍니다.

contents = []
# 형태소 분석, 명사만 추출
twitter.add_dictionary(['크리스마스','쇼미더머니','SK하이닉스'],'Noun')
for i in desc:
    contents.append(twitter.nouns(i))
text = [' '.join(contents[i]) for i in range(len(contents))]
print(text)

출력:

그 후 문장 벡터화를 하여 분석할 수 있는 형태로 텍스트를 바꾸어 줍니다.

#문장 벡터화
vectorize = CountVectorizer()
x = vectorize.fit_transform(text)

이렇게 준비가 되었으면 평균 군집 분석을 진행해 줍니다.

데이터 셋이 3개의 키워드로 검색후 만든 파일이기 때문에 k=3으로 설정하여 진행해 보도록 하겠습니다.

######### 평균 군집 분석 ###########
#데이터 프레임 생성 (문장 단어 매트릭스 만들기)
new_df = pd.DataFrame(x.toarray(), columns=vectorize.get_feature_names_out())

# K- 평균 군집 분석
kmeans = KMeans(n_clusters=3).fit(new_df)
print('[K-평균 군집 분석 결과]')
print('###########################################')

print(kmeans.labels_)

출력:

아까의 문장들이 k=3이라고 했기 때문에 0,1,2의 3 그룹 중 하나로 배정되었음을 확인할 수 있습니다.

K-대푯값 군집 분석

위의 데이터를 가지고 이번에는 대푯값 군집 분석을 진행하겠습니다.

k-대푯값은 보통 데이터들 중 어느 한 값만 매우 높거나 매우 작을때 평균값이 그 데이터들을 대표하지 못할 때 평균 아닌 다른 방법으로 중심값을 찾아야 할 때 쓰는 방법입니다.

숫자로 예를 들자면

[1,2,3,4,5,6,100] 이라는 데이터가 있을 때 

위 숫자들의 평균은 (1+2+3+4+5+6+100)/7 =17.28... 이 되는데, 이 평균이 숫자들의 값을 대표한다고 보기 어렵습니다.

이 때 중앙값인 4를 대푯값으로 정하는 등의 다른 방법이 필요하게 됩니다.

텍스트도 평균 값이 아닌 대푯값을 정하여 군집 분석을 진행해 보도록 하겠습니다.

초기 대푯값으로는 각 키워드의 기사들 중 임의의 기사를 1개씩 선정하여 initial_index_medoids에 세팅해 주었습니다.

######### k-대푯값 군집 분석 ###########
#인스턴스 생성
kmedoids_ins = kmedoids.kmedoids(new_df.values,initial_index_medoids=[4,18,36]) # initial_index는 df행 중 대푯값 행 지정
kmedoids_ins.process()
clusters = kmedoids_ins.get_clusters()
print('###########################################')
print('[K-대푯값 군집 분석 결과]')

print(clusters)

출력:

각각 []로 3개의 군집으로 나누어졌음을 확인할 수 있습니다. 

이번 텍스트에서는 k대푯값보다 kmeans가 더 분석이 잘 되었네요. 다른 텍스트로도 한 번 진행해 보시고 분석 목적에 맞는 방법을 선택해서 진행하면 됩니다 ㅎㅎ

전체코드
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.cluster import KMeans
from pyclustering.cluster import kmedoids
from ckonlpy.tag import Twitter
twitter = Twitter()
#데이터 불러오기
df = pd.read_csv('clustering_ex.csv')
print(df.head())

# 텍스트 전처리
import re
desc = df['요약']
for i in range(len(desc)):
    desc[i] = re.sub('(<b>|</b>|&quot;)','',desc[i])
#print(desc)
contents = []
# 형태소 분석, 명사만 추출
twitter.add_dictionary(['크리스마스','쇼미더머니','SK하이닉스'],'Noun')
for i in desc:
    contents.append(twitter.nouns(i))

#print(contents)
text = [' '.join(contents[i]) for i in range(len(contents))]
print(text)

#문장 벡터화
vectorize = CountVectorizer()
x = vectorize.fit_transform(text)

######### 평균 군집 분석 ###########
#데이터 프레임 생성 (문장 단어 매트릭스 만들기)
new_df = pd.DataFrame(x.toarray(), columns=vectorize.get_feature_names_out())

# K- 평균 군집 분석
kmeans = KMeans(n_clusters=3).fit(new_df)
print('[K-평균 군집 분석 결과]')
print('###########################################')

print(kmeans.labels_)


######### k-대푯값 군집 분석 ###########
#인스턴스 생성
kmedoids_ins = kmedoids.kmedoids(new_df.values,initial_index_medoids=[4,18,36]) # initial_index는 df행 중 대푯값 행 지정
kmedoids_ins.process()
clusters = kmedoids_ins.get_clusters()
print('###########################################')
print('[K-대푯값 군집 분석 결과]')

print(clusters)

 

참고자료
  • 책- 「잡아라 텍스트 마이닝 with 파이썬」
보너스 

PCA (주성분 분석)으로 군집 시각화하기

PCA(Principal component analysis)는 간단하게 말해 고차원의 데이터를 저차원의 데이터로 바꾸는 방법입니다.

여러 변수가 있으면 그 것을 융합해 주성분을 뽑아내어 그것을 새로운 변수로 만들어내는 방법입니다.여기서는 텍스트를 2차원으로 축소 후 결과를 시각화하여 보겠습니다.

#pca(주성분 분석)으로 시각화하기
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA(n_components=2) # 2차원으로 축소
pc = pca.fit_transform(new_df)
p_df = pd.DataFrame(data=pc, columns=['main1', 'main2'])
p_df.index=df['검색어']

plt.scatter(p_df.iloc[kmeans.labels_ == 0,0],
            p_df.iloc[kmeans.labels_ == 0,1], s = 10, c = 'red', label = 'clustering1')
plt.scatter(p_df.iloc[kmeans.labels_ == 1,0],
            p_df.iloc[kmeans.labels_ == 1,1], s = 10, c = 'blue', label = 'clustering2')
plt.scatter(p_df.iloc[kmeans.labels_ == 2,0],
            p_df.iloc[kmeans.labels_ == 2,1], s = 10, c = 'green', label = 'clustering3')

plt.legend()
plt.show()

주성분 분석에 대해 더 알아보고 싶은 분은 아래의 링크를 참고해 주세요 :)

https://www.youtube.com/watch?v=FgakZw6K1QQ

전체 코드 파일

text_clustering.py
0.00MB

반응형
반응형

Pandas는 데이터 분석을 할 때 필수적으로 사용하는 파이썬 라이브러리입니다.

오늘은 유용하게 쓰일 수 있는 판다스의 메소드 몇 가지를 간단히 알아보도록 하겠습니다.

Groupby 그룹바이

pandas.groupby() 메서드는 그룹 연산을 도와주는 메서드입니다.

데이터를 집계하면 전체 데이터를 더 분석하기 쉽고 한눈에 파악하는데 용이하기 때문에 groupby는 정말 유용합니다.

그룹바이를 이용하면 평균, 합, 표준편차 등등 여러 값을 구할 수 있습니다.

오늘은 저번에 bar_chart_race에서 사용한 코로나 확진자 데이터를 이용하여 집계해 보도록 하겠습니다.

데이터셋

corona_kr.csv
1.61MB

위의 데이터를 다운받아 주세요:)

그 후 파일을 열어 어떤 데이터를 가지고 있는지 확인해 보도록 하겠습니다.

####### Pandas Groupby #######

import pandas as pd

#데이터셋 준비
df = pd.read_csv('corona_kr.csv')
print(df.head())

출력:

이렇게 업데이트된 날짜, 사망인원, 확진자, 지역명(한국어) 등등 여러 정보가 나와 있습니다.

이 데이터는 2020년부터~2021년 11월 초반까지의 데이터입니다.

지역별 총 코로나 확진자 수를 groupby sum을 이용해 구해 보도록 하겠습니다.

사용방법은 아래와 같습니다.

df.groupby('합계를 구할 기준컬럼 이름').합계할 값 컬럼이름.하고싶은 그룹연산()

 

##### groupby sum #####
## 지역별 총 코로나 확진자 수 구하기##

corona_by_region= df.groupby('gubun').defCnt.sum()
print(corona_by_region)

출력:

이렇게 지역별 합이 만들어졌습니다.

이번에는 기간 내 코로나 확진자 지역 평균을 mean()을 사용하여 구해보도록 하겠습니다.

##### groupby mean #####
##지역별 평균 확진자 수  ##

means_by_region = df.groupby('gubun').defCnt.mean()

print(means_by_region)

출력:

이렇게 하루 평균 지역 확진자 발생 인원을 구했습니다.

마지막으로는 describe를 알아보도록 하겠습니다.

describe는 전체적인 집계 정보를 보여줍니다.

위에서 구한 합계, 평균뿐만 아니라 표준편차, 최솟값, 최댓값, 4 분위 값 등등을 확인할 수 있습니다.

##### groupby describe #####
#코로나 확진자에 대한 전체적인 정보 반환#
print(df.groupby('gubun').defCnt.describe())

출력:

이렇게 데이터에 대한 전체적인 정보를 describe를 사용하여 확인 할 수 있습니다 :)

 

pivot_table 피벗 테이블

pivot_table 메서드는 데이터 프레임의 행과 열의 위치를 내가 원하는 대로 배치할 수 있도록 도와줍니다.

코로나 데이터에서는 지역 컬럼이 따로 있고 하루마다 확진자 수가 갱신이 됩니다.

지역별 확진자 수를 한눈에 보기 위해 (1)열 수를 정리해주고,

피벗 테이블을 사용하여 (2)지역열에 있는 행값들을 열로 위치하고, 

각 지역 (3)열 값의 값으로는 확진자 수(defCnt)를 넣어 주도록 하겠습니다.

#### pandas pivot table ####
#필요한 정보만 df2에 담기
df2 = df.iloc[:,1:5]
print(df2)

출력:

corona_pivotTable = df2.pivot_table(
                    index=['createDt','deathCnt'],
                    columns='gubun',
                    values='defCnt' )
print(corona_pivotTable)

출력:

[원본 데이터]

[피벗 후 데이터]

위와 같이 아까는 행에 있던 지역 명들이 열값으로 옮겨졌음을 확인할 수 있습니다.

pivot_table 메서드에서 3개의 인자를 사용하여 데이터프레임을 피봇 해주었는데요,

index =  그대로 유지할 열 이름 입력

columns = 피벗할 열 이름 입력

values = 피벗할 열의 값이 될 열 이름 입력

위와 같이 사용하여 입력하면 됩니다:)

melt

마지막으로 알아볼 메서드는 melt인데요,

melt는 긴 열값을 가지고 있는 데이터를 정리할 때 유용합니다.

예를 들어 서울시 상권분석서비스 소득소비 데이터를 확인해보면,

(아래의 링크에서 데이터를 다운받아 주세요.)

http://data.seoul.go.kr/dataList/OA-15571/S/1/datasetView.do

 

열린데이터광장 메인

데이터분류,데이터검색,데이터활용

data.seoul.go.kr

##데이터 셋 불러오기##
seoul=pd.read_csv('서울시_우리마을가게 상권분석서비스(상권배후지-소득소비).csv',encoding='cp949')
print(seoul)

출력:

위와 같이 의류지출총금액, 생활용품지출총금액, 의료지출금액 등등 열이 길게 늘어져 있는것을 확인할 수 있습니다.

이 데이터를 melt를 사용해서 지출 종류별로 열을 행으로 만들어 주어 데이터를 만들어 보도록 하겠습니다.

행으로 합쳐질 새로운 열의 이름을 '지출 종류'라 이름짓고, 원래 데이터에 있던 지출금액을 '금액'으로 열이름을 지정하겠습니다.

#### pandas melt ####
seoul_melt = pd.melt(seoul,id_vars=['기준 년 코드','기준_분기_코드','상권_구분_코드','상권_구분_코드_명',
                                    '상권_코드','상권_코드_명','월_평균_소득_금액'
                                    , '소득_구간_코드','지출_총금액']
                    , var_name='지출종류',value_name='금액')
# 변경된 부분 한눈에 확인할 수 있도록 앞에 부분 자르기
a = seoul_melt.iloc[:,8:]
print(a)

출력:

위와 같이 아까는 열이었던 식료품, 유흥, 의료 지출 총 금액이 하나의 열의 행값으로 합쳐지고 그 값도 옆에 '금액' 열로 정리되었음을 확인할 수 있습니다.

melt 메서드 인자는 아래와 같이 사용할 수 있습니다.

id_vars = 그대로 유지할 열 이름, 2개이상 입력 시 []로 묶어 입력하기

value_vars = 행으로 바꿀 열 이름

var_name = value_vars로 바꿀 열의 새로운 이름 만들기

value_name =  var_name으로 바꾼 열의 원래 데이터값의 새로운 열 이름

 

전체 코드
####### Pandas Groupby #######

import pandas as pd

#데이터셋 준비
df = pd.read_csv('corona_kr.csv')
print(df.head())


##### groupby sum #####
## 지역별 총 코로나 확진자 수 구하기##

corona_by_region= df.groupby('gubun').defCnt.sum()
print(corona_by_region)

##### groupby mean #####
##지역별 평균 확진자 수  ##

means_by_region = df.groupby('gubun').defCnt.mean()

print(means_by_region)

##### groupby describe #####
#코로나 확진자에 대한 전체적인 정보 반환#
print(df.groupby('gubun').defCnt.describe())


#### pandas pivot table ####
df2 = df.iloc[:,1:5]
print(df2)
corona_pivotTable = df2.pivot_table(
                    index=['createDt','deathCnt'],
                    columns='gubun',
                    values='defCnt' )
print(corona_pivotTable)



#### pandas melt ####


##데이터 셋 불러오기##
seoul=pd.read_csv('서울시_우리마을가게 상권분석서비스(상권배후지-소득소비).csv',encoding='cp949')
print(seoul)

seoul_melt = pd.melt(seoul,id_vars=['기준 년 코드','기준_분기_코드','상권_구분_코드','상권_구분_코드_명',
                                    '상권_코드','상권_코드_명','월_평균_소득_금액'
                                    , '소득_구간_코드','지출_총금액']
                    , var_name='지출종류',value_name='금액')
a = seoul_melt.iloc[:,8:]
print(a)

 

코드 파일

groupby_pivot.py
0.00MB

참고 자료

책 「데이터 분석을 위한 판다스 입문」 - 이지스퍼블리싱

마무리

오늘은 데이터 전처리 시 유용하게 사용가능한 메서드 3개를 알아보았습니다ㅎㅎ

알고싶은 다른 pandas 기능이 있으시다면 댓글로 남겨주세요 (o'◡'o)

반응형
반응형
텍스트  유사도란?

빅스비나 시리에게 아래와 같은 내용을 물어본다고 가정합시다.

  • (시리야,빅스비야) 이 요리의 레시피가 뭐야?
  • (시리야,빅스비야)  이 요리 어떻게 만들어?

이때 두 문장은 같은 의미를 가지고 있지만 컴퓨터는 두 문장을 각각 다른 문장이라 볼 것입니다.

물어보는 내용은 살짝 다르지만 핵심 의미는 같아 시리나 빅스비가 대답을 할 때는 요리 방법을 알려주는 내용을 똑같이 알려주면 될 것입니다.

이렇듯 의미가 비슷한 두 문장이 얼마나 비슷한지 알아보는 것을 '텍스트 유사도(Text Similarity)'라고 합니다.

또한 위와 같은 질문들을 컴퓨터가 인식하려면 두 문장이 서로 얼마나 비슷한지 측정하는 과정을 거쳐야 합니다.

이런 상황에서 여러 텍스트 유사도 측정 방법을 사용하여 두 문장 사이의 유사도를 측정할 수 있습니다.

오늘 포스팅은 딥러닝 기반의 텍스트 유사도 측정 방법을 알아보도록 하겠습니다.

이 방법은 텍스트를 벡터화(임베딩) 후 각 문장의 유사도를 측정하는 방식입니다.

 

텍스트 벡터화란?

텍스트 벡터(vector)화는

사람이 사용하는 자연어를 기계가 알아들을 수 있도록 0과 1로 수치화하여 나타내는 것을 말합니다.

문장 안에 단어들을 벡터화시키는 방법 중 기본 방법은 원-핫 인코딩(one-hot encoding)이 있습니다.

예를 들어, 컴퓨터에게 요리, 주방, 칼, 포크 이렇게 4 단어를 알려준다고 가정해 봅시다.

이때 원핫인코딩을 사용하면 벡터의 크기는 아래와 같이 4가 됩니다.

요리 주방 포크

4 단어의 4벡터값

여기서 각 단어를 그 단어에 해당하는 벡터 값의 인덱스를 1로 표현해 주면 그 단어의 벡터 값이 만들어집니다.

요리 = [1, 0, 0, 0]

주방 = [0, 1, 0, 0]

칼 = [0, 0, 1, 0]


포크 = [0, 0, 0, 1]

이런 식으로 각 단어가 원핫 인코딩이 됩니다.

유사도를 구할 때는 Tfidf 벡터 값을 사용하여 측정해 보겠습니다.

TF-IDF란?
  • TF(Term Frequency): 한 단어가 하나의 데이터 안에서 등장하는 횟수
  • DF(Document Frequency): 문서 빈도 값, 어떤 단어가 다른 문장에도 자주 등장하는지 알려주는 지표.
  • IDF(Inverse Document Frequency): DF값의 역수
  • TF-IDF = TF x IDF

TF-IDF는 한 단어가 해당 문서에 자주 등장하지만 다른 문서에는 없는 단어일수록 높은 값을 가집니다.

일반 빈도 계산으로는 조사(은/는/이/가), 지시대명사(그, 그것, 이)등의 카운트가 가장 높이 잡히는데

(워드 클라우드에서는 이런 값이 많이 잡히면 불용어 처리를 해줍니다.)

TF-IDF는 이런 조사 값이 많을수록 점수가 낮아져 일반 빈도 계산에서의 문제를 해결해 줍니다.

이제 유사도를 구하는 방법을 알아보도록 합시다.

 

유사도 측정을 위한 라이브러리 설치

우선 딥러닝, 머신러닝을 사용하기 위해 아래의 명령어를 사용하여 tensorflow와 사이킷런 라이브러리를 설치해 줍니다.

pip install tensorflow #텐서플로우 설치
pip install sklearn #사이킷런 설치

 

코사인 유사도

코사인 유사도는 두 개의 문장의 벡터 값에서 코사인 각도를 구하는 방법입니다.

-1~1 사이의 값을 가지며

-1 --------------------------------------------------- 1

다름                                                      완전일치

위와 같이 1에 가까울수록 두 문장이 유사함을 나타냅니다.

"이 요리의 레시피를 알려줘."

"이 요리 어떻게 만드는지 알려줘."

이 두 문장을 사용하여 문장 사이의 유사도가 얼마나 되는지 측정해 보도록 하겠습니다.

1. 사이킷런 TfidfVectorizer의 객체 생성
2. .fit_transform() 메서드를 사용하여 tfid벡터화
3. 두 문장을 비교하여 유사도 측정 

위의 3 과정을 거치는 코드를 작성해 줍니다.

####### 텍스트 유사도 측정 ######
from sklearn.feature_extraction.text import TfidfVectorizer
sentences = ("이 요리 의 레시피 를 알려줘.",
        "이 요리 어떻게 만드는 지 알려줘.")
tfidf_vectorizer = TfidfVectorizer()

# 문장 벡터화 하기(사전 만들기)
tfidf_matrix = tfidf_vectorizer.fit_transform(sentences)

### 코사인 유사도 ###
from sklearn.metrics.pairwise import cosine_similarity
# 첫 번째와 두 번째 문장 비교
cos_similar = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])
print("코사인 유사도 측정")
print(cos_similar)

출력:

코사인 유사도 측정
[[0.41120706]]

두 문장의 코사인 유사도는 0.411입니다.

 

유클리디언 유사도

유클리디언 유사도는 가장 기본거리를 측정하는 공식입니다.

중고등학교 수학에서 배우는 좌표평면의 두 점 사이의 거리를 구하는 것을 '유클리디언 거리'라고 합니다.

또한 L2거리(L2-Distance)라고도 불립니다.

유클리디언 유사도는 거리이기 때문에 결괏값이 1이 넘을 수 있습니다.

이를 방지하기 위해, 0과 1 사이의 값을 갖도록 만들어 줍니다.

벡터화 시, vector값의 합으로 나누어 정규화 후 유사 값을 구해주도록 하겠습니다.

### 유클리디언 유사도 (두 점 사이의 거리 구하기) ###
import numpy as np
from sklearn.metrics.pairwise import euclidean_distances

## 정규화 ##
tfidf_normalized = tfidf_matrix/np.sum(tfidf_matrix)

##유클리디언 유사도##
euc_d_norm = euclidean_distances(tfidf_normalized[0:1],tfidf_normalized[1:2])
print("유클리디언 유사도 측정")
print(euc_d_norm)
유클리디언 유사도 측정
[[0.29486722]]

정규화 후 유클리언 유사도는 0.295가 나왔습니다.

 

맨하탄 유사도

맨하탄 유사도(Manhattan Similarity)는 맨하탄 거리를 통해 유사도를 구하는 방법을 말합니다.

맨하탄 거리는 사각 격자로 이루어진 지도에서 출발에서 도착까지의 최단 거리를 구하는 공식입니다.

또한 L1거리(L1-Distance)라고도 불립니다.

맨하탄 거리도 측정 값이 1이 넘을 수 있어 정규화 된 값을 사용하여 구해주도록 하겠습니다.

### 맨하탄 유사도(격자로 된 거리에서의 최단거리) ###
from sklearn.metrics.pairwise import manhattan_distances
manhattan_d = manhattan_distances(tfidf_normalized[0:1],tfidf_normalized[1:2])
print("맨하탄 유사도 측정")
print(manhattan_d)
맨하탄 유사도 측정
[[0.5544387]]

맨하탄 유사도는 0.554로 3가지의 방법 중 측정값이 제일 크게 나왔습니다.

전체 코드
####### 텍스트 유사도 측정 ######
from sklearn.feature_extraction.text import TfidfVectorizer
sentences = ("이 요리 의 레시피 를 알려줘.",
        "이 요리 어떻게 만드는 지 알려줘.")
tfidf_vectorizer = TfidfVectorizer()
 # 문장 벡터화 하기(사전 만들기)
tfidf_matrix = tfidf_vectorizer.fit_transform(sentences)

### 코사인 유사도 ###
from sklearn.metrics.pairwise import cosine_similarity
# 첫 번째와 두 번째 문장 비교
cos_similar = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])
print("코사인 유사도 측정")
print(cos_similar)

### 유클리디언 유사도 (두 점 사이의 거리 구하기) ###
import numpy as np
from sklearn.metrics.pairwise import euclidean_distances

## 정규화 ##
tfidf_normalized = tfidf_matrix/np.sum(tfidf_matrix)

##유클리디언 유사도##
euc_d_norm = euclidean_distances(tfidf_normalized[0:1],tfidf_normalized[1:2])
print("유클리디언 유사도 측정")
print(euc_d_norm)

### 맨하탄 유사도(격자로 된 거리에서의 최단거리) ###
from sklearn.metrics.pairwise import manhattan_distances
manhattan_d = manhattan_distances(tfidf_normalized[0:1],tfidf_normalized[1:2])
print("맨하탄 유사도 측정")
print(manhattan_d)
코드 파일

text_similarity.py
0.00MB

참고 문서

책- 텐서플로2와 머신러닝으로 시작하는 자연어처리(로지스틱 회귀부터 BERT와 GPT2까지)

마무리

오늘은 텍스트 유사도 측정의 3가지 방법을 알아보았는데요

각 측정법마다 유사도가 크게 다른 것을 확인할 수 있었습니다.

때문에 텍스트 분석 시 분석 방향에 맞는 유사도 측정 방법을 잘 선택하시길 바랍니다( ͡• ͜ʖ ͡• )

반응형
반응형

한국어 전처리에 이어, 오늘은 영어 전처리를 알아 보도록 하겠습니다:)

영어 자연어처리는 대표적인 2개의 라이브러리가 있습니다.

  • NLTK(Natural Language ToolKit)
  • spaCy

이렇게 2가지가 있는데 두 가지 다 사용하여 전처리 해보도록 하겠습니다.

설치

라이브러리 설치는 아나콘다 프롬프트 창을 열고 아래와 같이 명령어를 입력하여 설치해 주세요.

[nltk 설치]

conda install nltk

[spaCy 설치]

conda install spacy
문장 토크나이징

자연어 처리를 할 때는 보통 텍스트에 대한 정보를 단위별로 나누어 전처리를 합니다.

이 때 토크나이징이 필요한데요, 이는 문장을 특정 기본 단위로 나누어 줍니다.

설치가 완료되었으면 한 문장을 예시로 각각의 라이브러리를 사용해서 단어 및 문장별로 나누어 주겠습니다.

문장은 spacy에서 기본적으로 제공하는 문장 중 하나를 선택하여 사용하겠습니다.

import nltk
from nltk.tokenize import word_tokenize
from nltk.tokenize import sent_tokenize
import spacy
from spacy.lang.en.examples import sentences
nlp = spacy.load('en_core_web_sm')
#문장 불러오기
doc = nlp(sentences[0])
print('원래 문장')
print(doc.text) #예시문장
원래 문장
Apple is looking at buying U.K. startup for $1 billion

위의 문장을 단어별로, 문장별로 토크나이징 해주도록 하겠습니다.

##### nlkt 토크나이징 #####
print('nlkt로 단어 토크나이징')
print(word_tokenize(doc.text))

print('nlkt로 문장 토크나이징')
print(sent_tokenize(doc.text))

##### spacy 토크나이징 #####
print('spacy로 단어 토크나이징')
spacy_word = [word.text for word in doc] #단어
print(spacy_word)

print('spacy로 문장 토크나이징')
spacy_sentence = [sentence.text for sentence in doc.sents] #문장
print(spacy_sentence)
nlkt로 단어 토크나이징
['Apple', 'is', 'looking', 'at', 'buying', 'U.K.', 'startup', 'for', '$', '1', 'billion']

nlkt로 문장 토크나이징
['Apple is looking at buying U.K. startup for $1 billion']

spacy로 단어 토크나이징
['Apple', 'is', 'looking', 'at', 'buying', 'U.K.', 'startup', 'for', '$', '1', 'billion']

spacy로 문장 토크나이징
['Apple is looking at buying U.K. startup for $1 billion']

위와 같이 nltk, spacy에서 동일한 결과를 출력하는 것을 알 수 있습니다.

어간 추출(Stemming)

예시 문장을 보면 looking과 같은 단어는 동사 look(보다)에서 변형되었음을 알 수 있습니다.

looking 은 look이랑 같은 의미를 갖습니다.

하지만 컴퓨터는 look, looking 모두 다른 단어로 인식하기 때문에

어간 동일화를 하여 원래의 형태로 바꾸어 추출해주는 과정을 거칩니다.

이를 스테밍(Stemming) 또는 '어간 동일화'라고 합니다.

Stemming은 nltk에서만 제공하는 기능이어서 nltk로 진행해보도록 하겠습니다.

nltk의 stem에는 3가지 종류의 stemmer가 있습니다.

그 종류는 아래와 같습니다.

  • PorterStemmer
  • LancasterStemmer
  • RegexpStemmer

이 중 RegexpStemmer는 특정 단어를 일괄 제거해 주는 stemmer입니다.

#### 어간 추출 ####
a = word_tokenize(doc.text)
from nltk.stem import PorterStemmer, LancasterStemmer, RegexpStemmer
porter_stemmer, lancaster_stemmer = PorterStemmer(),LancasterStemmer()
porter = [porter_stemmer.stem(i) for i in a]
print("PorterStemmer 사용하여 어간추출")
print(porter)

lancaster = [lancaster_stemmer.stem(i) for i in a]
print("LancasterStemmer 사용하여 어간추출")
print(lancaster)

regexp_stemmer = RegexpStemmer("Apple") # ()안 특정 표현식 일괄 제거
regexp = [regexp_stemmer.stem(i) for i in a]
print("RegexpStemmer 사용하여 특정 단어 제거")
print(regexp)
PorterStemmer 사용하여 어간추출
['appl', 'is', 'look', 'at', 'buy', 'u.k.', 'startup', 'for', '$', '1', 'billion']

LancasterStemmer 사용하여 어간추출
['appl', 'is', 'look', 'at', 'buy', 'u.k.', 'startup', 'for', '$', '1', 'bil']

RegexpStemmer 사용하여 특정 단어 제거
['', 'is', 'looking', 'at', 'buying', 'U.K.', 'startup', 'for', '$', '1', 'billion']

결과를 보면, looking을 look으로, buying을 buy로 추출한 것을 알 수 있습니다.

품사 분석

한국어 전처리와 마찬가지로 영어에도 pos(part-of-speech)라는 품사 분석기가 있습니다.

nltk, spacy 모두 사용해 보겠습니다.

####품사태깅####

## nltk ##
print('nltk 품사 태깅')
print(nltk.pos_tag(a))

## spacy ##
print('spacy 품사 태깅')
tag = [(tag.text ,tag.tag_) for tag in doc]
print(tag)
nltk 품사 태깅
[('Apple', 'NNP'), ('is', 'VBZ'), ('looking', 'VBG'), ('at', 'IN'), ('buying', 'VBG'), ('U.K.', 'NNP'), ('startup', 'NN'), ('for', 'IN'), ('$', '$'), ('1', 'CD'), ('billion', 'CD')]

spacy 품사 태깅
[('Apple', 'NNP'), ('is', 'VBZ'), ('looking', 'VBG'), ('at', 'IN'), ('buying', 'VBG'), ('U.K.', 'NNP'), ('startup', 'VBD'), ('for', 'IN'), ('$', '$'), ('1', 'CD'), ('billion', 'CD')]

이렇게 각각의 단어마다 품사 태그를 한 것을 확인할 수 있습니다.

품사 태그의 의미 및 종류는 아래의 링크에서 확인해 주세요:)

품사 태그 리스트

 

POS Tagging with NLTK and Chunking in NLP [EXAMPLES]

POS Tagging Parts of speech Tagging is responsible for reading the text in a language and assigning some specific token (Parts of Speech) to each word.

www.guru99.com

 

전체 코드
import nltk
from nltk.tokenize import word_tokenize
from nltk.tokenize import sent_tokenize
import spacy
from spacy.lang.en.examples import sentences
nlp = spacy.load('en_core_web_sm')
#문장 불러오기
doc = nlp(sentences[0])
print('원래 문장')
print(doc.text) #예시문장

##### nlkt 토크나이징 #####
print('nlkt로 단어 토크나이징')
print(word_tokenize(doc.text))

print('nlkt로 문장 토크나이징')
print(sent_tokenize(doc.text))

##### spacy 토크나이징 #####
print('spacy로 단어 토크나이징')
spacy_word = [word.text for word in doc] #단어
print(spacy_word)

print('spacy로 문장 토크나이징')
spacy_sentence = [sentence.text for sentence in doc.sents] #문장
print(spacy_sentence)

#### 어간 추출 ####
a = word_tokenize(doc.text)
from nltk.stem import PorterStemmer, LancasterStemmer, RegexpStemmer
porter_stemmer, lancaster_stemmer = PorterStemmer(),LancasterStemmer()
porter = [porter_stemmer.stem(i) for i in a]
print("PorterStemmer 사용하여 어간추출")
print(porter)

lancaster = [lancaster_stemmer.stem(i) for i in a]
print("LancasterStemmer 사용하여 어간추출")
print(lancaster)

regexp_stemmer = RegexpStemmer("Apple") # ()안 특정 표현식 일괄 제거
regexp = [regexp_stemmer.stem(i) for i in a]
print("RegexpStemmer 사용하여 특정 단어 제거")
print(regexp)

####품사태깅####

## nltk ##
print('nltk 품사 태깅')
print(nltk.pos_tag(a))

## spacy ##
print('spacy 품사 태깅')
tag = [(tag.text ,tag.tag_) for tag in doc]
print(tag)
코드 파일

nlp_nltk_spacy.py
0.00MB

참고 자료
  • 책 「잡아라! 텍스트 마이닝 with 파이썬」
  • 책 「텐서플로 2와 머신러닝으로 시작하는 자연어처리-로지스틱회귀부터 BERT와 GPT2까지」
  • spaCy 공식 사이트
 

English · spaCy Models Documentation

spaCy is a free open-source library for Natural Language Processing in Python. It features NER, POS tagging, dependency parsing, word vectors and more.

spacy.io

 

NLTK :: Natural Language Toolkit

Natural Language Toolkit NLTK is a leading platform for building Python programs to work with human language data. It provides easy-to-use interfaces to over 50 corpora and lexical resources such as WordNet, along with a suite of text processing libraries

www.nltk.org

마무리

오늘은 영어 전처리 방법을 간단히 알아보았습니다.

nltk나 spacy 중 편한 라이브러리를 사용하여 영어 전처리 하면 될 것 같습니다 ㅎㅎ

영어 말고도 다른 언어도 지원하니 관심이 있는 분은 공식 문서를 사용하여 분석 진행하시면 됩니다. o(〃^▽^〃)o

제 포스팅 항상 봐주셔서 감사합니다. ლ(╹◡╹ლ)

반응형
반응형

오늘은 konlpy(코엔엘파이)의 4개의 라이브러리(Okt, Kkma, Komoran, Hannanum)로

한국어 형태소를 분석해 보도록 하겠습니다.

그 전에 국어에서 사용하는 용어들을 정리해 보도록 하겠습니다.

 

형태소란?

형태소(形態素)는 '뜻을 가진 가장 작은 말의 단위'로(출처: 국립국어원 표준국어대사전),

더 이상 나누게 되면 그 의미가 없어지는 것들을 말합니다.

예를 들어,

'책가방' 은 '책', '가방' 이 두가지가 형태소라고 말 할 수 있습니다.

가방에서 가/방 으로 나누면 더이상 가방의 의미가 아니게 되니까 최소 단위가 '가방'이 된다고 볼 수 있습니다.

어간이란?

어간(語幹)은 '활용어가 활용할 때에 변하지 않는 부분'을 말합니다.(출처: 국립국어원 표준국어대사전)

예를 들어, 동사 '보다'의 경우 '보았다(과거), 보니, 보고' 등으로 활용될 수 있는데

이들의 어간은 '보-'가 된다고 볼 수 있습니다.

어절이란?

어절(語節)은 '문장을 구성하고 있는 각각의 마디'를 말하며,

문장 성분의 최소 단위로서 띄어쓰기의 단위가 됩니다.(출처: 국립국어원 표준국어대사전)

'나는 자연어 처리 공부를 한다.'

위의 문장을 보면

'나는 / 자연어/ 처리/ 공부를/ 한다.'

이렇게 5개로 나눌 수 있는데 이것이 각각 어절이 된다고 볼 수 있습니다.

품사란?

품사(品詞)는 '단어를 기능, 형태, 의미에 따라 나눈 갈래' 라고 합니다.(출처: 국립국어원 표준국어대사전)

대표적으로 의미에 따라

  1. 명사: 사물의 이름을 나타내는 품사 ex) 사과, 달, 별
  2. 대명사: 사람이나 사물의 이름을 대신 나타내는 말 ex) 무엇, 이것, 저기
  3. 수사: 사물의 수량이나 순서를 나타내는 품사 ex) 하나, 둘, 셋, 일, 이, 삼
  4. 조사: 체언이나 부사, 어미 따위에 붙어 그 말과 다른 말과의 문법적 관계를 표시하거나 그 말의 뜻을 도와주는 품사 ex) 은, 는, 이, 가
  5. 동사: 사물의 동작이나 작용을 나타내는 품사 ex) 보다, 먹다, 자다, 일어나다
  6. 형용사: 사물의 성질이나 상태를 나타내는 품사 ex) 시원하다, 귀엽다, 기쁘다
  7. 관형사: 체언 앞에 놓여서, 그 체언의 내용을 자세히 꾸며 주는 품사 ex) 새, 옛, 윗, 뒷
  8. 부사: 용언 또는 다른 말 앞에 놓여 그 뜻을 분명하게 하는 품사 ex) 빨리, 다행히, 매우
  9. 감탄사: 말하는 이의 본능적인 놀람이나 느낌, 부름, 응답 따위를 나타내는 말의 부류 ex)아이고, 아차, 와

이렇게 9가지로 분류할 수 있습니다. (출처: 국립국어원 표준국어대사전)

 

형태소 분석 개체 생성

간단히 용어를 알아보았으니, 이제는 형태소 단위로 토크나이징 하는 방법을 알아보도록 합시다.

토크나이징(tokenizing)은 텍스트 정보를 단위별로 나누는 것을 말합니다.

konlpy의 분석기 종류는 총 5가지가 있습니다.

  •  Kkma
  • Okt
  • Komoran
  • Hannanum
  • Mecab

위의 5개인데, Mecab은 윈도우에서 작동이 불가능해

이번 포스팅에는 Mecab을 제외한 4가지를 사용하여 형태소를 분석해 보겠습니다.

####한국어 형태소 분석기####
from konlpy.tag import Kkma, Komoran, Okt, Hannanum #Mecab은 윈도우에서 작동 불가능
okt = Okt()
kkma = Kkma()
komoran = Komoran()
hannanum = Hannanum()

그 다음, 텍스트를 준비해 줍니다. 여기서는 '훈민정음'의 서문의 일부 내용을 준비하였습니다.

text = '나랏말이 중국과 달라 한자와 서로 통하지 아니하므로, \
    우매한 백성들이 말하고 싶은 것이 있어도 마침내 제 뜻을 잘 표현하지 못하는 사람이 많다.\
    내 이를 딱하게 여기어 새로 스물여덟 자를 만들었으니, \
    사람들로 하여금 쉬 익히어 날마다 쓰는 데 편하게 할 뿐이다.'
morphs로 형태소 분석

.morphs 함수는 텍스트를 형태소 단위로 나누어 줍니다.

#### .morphs()함수: 텍스트를 형태소 단위로 나누어준다.####
print("[Kkma morphs 함수]")
print(kkma.morphs(text))
print("[Okt 함수]")
print(okt.morphs(text))
print("[Komoran 함수]")
print(komoran.morphs(text))
print("[Hannanum 함수]")
print(hannanum.morphs(text))
[Kkma morphs 함수]
['나랏말', '이', '중국', '과', '닿', 'ㄹ라', '한자', '와', '서로', '통하', '지', '아니하', '므로', ',', '우매', '하', 'ㄴ', '백성', '들', '이', '말하', '고', '싶', '은', '것', '이', '있', '어도', '마침내', '저', '의', '뜻', '을', '잘', '표현', '하', '지', '못하', '는', '사람', '이', '많', '다', '.', '내', '이르', 'ㄹ', '딱하', '게', '여기', '어', '새로', '스물', '여덟', '자', '를', '만들', '었', '으니', ',', '사람', '들', '로', '하여금', '쉬', '익히', '어', '날', '마다', '쓰', '는', '데', '편하', '게', '하', 'ㄹ', '뿐', '이', '다', '.']
[Okt 함수]
['못', '하는', '사람', '이', '많다', '.', '내', '이를', '딱하게', '여기어', '새로', '스물', '여덟', '자를', '만들었으니', ',', '사람', '들', '로', '하여금', '쉬', '익히어', '날', '마다', '쓰는', '데', '편하게', '할', '뿐', '이 다', '.'] [Komoran 함수] ['나랏말이', '중국', '과', '다르', '아', '한자', '와', '서로', '통하', '지', '아니하', '므로', ',', '우매', '하', 'ㄴ', '백성', '들', '이', '말', '하', '고', '싶', '은', '것', '이', '있', '어도', '마침내', '제', '뜻', '을', '잘', '표현', '하', '지', '못하', '는', '사람', '이', '많', '다', '.', '내', '이', '를', '딱하', '게', '여기', '어', '새로', '스물', '여덟', '자', '를', '만들', '었', '으니', ',', '사람', '들', '로', '하여금', '쉬', '익히', '어', '날', '마다', '쓰', '는', '데', '편하', '게', '하', 'ㄹ', '뿐', '이', '다', '.']
[Hannanum 함수]
['나랏말', '이', '중국', '과', '다르', '아', '하', 'ㄴ', '자', '와', '서로', '통하', '지', '아니하', '므로', ',', '우매', '하', 'ㄴ', '백성들', '이', '말', '하고', '싶', '은', '것', '이', '있', '어도', '마침내', '저', '의', '뜻', '을', '잘', '표현', '하', '지', '못하', '는', '사람', '이', '많', '다', '.', '내', '이', '를', '딱하', '게', '여기', '이', '어', '새로', '스물여덟', '자', '를', '만들', '었으니', ',', '사람들', '로', '하여금', '쉬', '

각각의 라이브러리로 형태소 분석이 완료되었습니다.

조금씩 차이가 있지만 대부분 비슷하게 분석이 되었습니다.

Okt에는 추가로 norm과 stem이라는 옵션이 있습니다.

norm은 문장을 정규화해주고, stem은 각 단어에서 어간을 추출해 줍니다.

오늘은 stem을 사용해 어간을 추출해 보겠습니다.

stem = True로 파라미터를 추가해 주면 적용됩니다.

##### stem: 각 단어에서 어간 추출 #####
print("[Okt 함수: stem사용하여 어간 추출]")
print(okt.morphs(text, stem= True))
[Okt 함수: stem사용하여 어간 추출]
['나랏말', '이', '중국', '과', '달라', '한자', '와', '서로', '통', '하다', '아니다', ',', '우매', '한', '백성', '들', '이', '말', '하고', '싶다', '것', '이', '있다', '마침내', '제', '뜻', '을', '자다', '표현', '하다', '못', 다', '.']

morphs와 비교해 보면 아니하므로 -> 아니하다, 딱하게-> 딱하다 등의 어간으로 바뀐것을 확인할 수 있습니다.

nouns로 명사 추출

.nouns는 품사 중 명사를 추출해 주는 함수입니다.

#### .nouns()함수: 명사를 추출 ####
print("[Kkma nouns 함수]")
print(kkma.nouns(text))
print("[OKt nouns 함수]")
print(okt.nouns(text))
print("[Komoran nouns 함수]")
print(komoran.nouns(text))
print("[Hannanum nouns 함수]")
print(hannanum.nouns(text))
[Kkma nouns 함수]
['나랏말', '중국', '한자', '우매', '백성', '저', '뜻', '표현', '사람', '내', '스물', '스물여덟', '여덟', '자', '로', '날', '데', '뿐'] [OKt nouns 함수]
['나랏말', '중국', '달라', '한자', '서로', '통', '우매', '백성', '말', '것', '마침내', '제', '뜻', '표현', '사람', '내', '스물', '여덟', '사람', '쉬', '날', '데', '뿐']
[Komoran nouns 함수]
['중국', '한자', '우매', '백성', '말', '것', '뜻', '표현', '사람', '자', '사람', '날', '데', '뿐']
[Hannanum nouns 함수]
['나랏말', '중국', '자', '우매', '백성들', '말', '것', '저', '뜻', '표현', '사람', '내', '이', '여기', '스물여덟', '자', '사람들', '데', '뿐']

이렇게 명사들이 추출됨을 확인할 수 있습니다.

phrases로 어절 추출하기

.phrases는 어절을 뽑아주는 함수입니다. Okt 라이브러리에만 있어 okt를 사용하여 어절 추출을 하겠습니다.

print("[Okt phrases 함수]")
print(okt.phrases(text))
[Okt phrases 함수]
['나랏말', '중국', '중국과 달라', '중국과 달라 한자', '중국과 달라 한자와 서로', '중국과 달라 한자와 서로 통', '우매', '백성들', '마침내', '마침내 제', '마침내 제 뜻', '표현', '못하는 사람', '스물여덟', '사람들', '달라', '한 자', '서로', '사람', '스물', '여덟']
pos를 사용하여 형태소 분석 및 태깅하기

마지막 함수인 .pos는 문장의 각 품사를 태깅해 줍니다.

예를 들어 '애벌레가 사과를 먹는다.' 에서 

애벌레 -> 명사

-> 조사

사과 - >명사

-> 조사

먹는다-> 동사

위와 같이 각각의 형태소에 품사이름을 붙여 줍니다.

#### .pos()함수: 품사 태깅 #### 
print("[Kkma pos 함수]")
print(kkma.pos(text)) #join=True는 형태소와 품사를 붙여서 리스트화
print("[Okt pos 함수]")
print(okt.pos(text))
print("[Komoran pos 함수]")
print(komoran.pos(text))
print("[Hannanum pos 함수]")
print(hannanum.pos(text))
[Kkma pos 함수]
[('나랏말', 'UN'), ('이', 'JKS'), ('중국', 'NNG'), ('과', 'JKM'), ('닿', 'VV'), ('ㄹ라', 'ECD'), ('한자', 'NNG'), ('와', 'JKM'), ('서로', 'MAG'), ('통하', 'VV'), ('지', 'ECD'), ('아니하', 'VXV'), ('므로', 'ECD'), (',', 'SP'), ('우매', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('백성', 'NNG'), ('들', 'XSN'), ('이', 'JKS'), ('말하', 'VV'), ('고', 'ECE'), ('싶', 'VXA'), ('은', 'ETD'), ('것', 'NNB'), ('이', 'JKS'), ('있', 'VV'), ('어도', 'ECD'), ('마침 내', 'MAG'), ('저', 'NP'), ('의', 'JKG'), ('뜻', 'NNG'), ('을', 'JKO'), ('잘', 'MAG'), ('표현', 'NNG'), ('하', 'XSV'), ('지', 'ECD'), ('못하', 'VX'), ('는', 'ETD'), ('사람', 'NNG'), ('이', 'JKS'), ('많', 'VA'), ('다', 'EFN'), ('.', 'SF'), ('내', 'NP'), ('이르', 'VV'), ('ㄹ', 'ETD'), ('딱하', 'VA'), ('게', 'ECD'), ('여기', 'VV'), ('어', 'ECD'), ('새로', 'MAG'), ('스물', 'NR'), ('여덟', 'NR'), ('자', 'NNG'), ('를', 'JKO'), ('만들', 'VV'), ('었', 'EPT'), ('으니', 'ECD'), (',', 'SP'), ('사람', 'NNG'), ('들', 'XSN'), ('로', 'NNG'), ('하여금', 'MAG'), ('쉬', 'MAG'), ('익히', 'VV'), ('어', 'ECD'), ('날', 'NNG'), ('마다', 'JX'), ('쓰', 'VV'), ('는', 'ETD'), ('데', 'NNB'), ('편하', 'VA'), ('게', 'ECD'), ('하', 'VV'), ('ㄹ', 'ETD'), ('뿐', 'NNB'), ('이', 'VCP'), ('다', 'EFN'), ('.', 'SF')]
[Okt pos 함수]
[('나랏말', 'Noun'), ('이', 'Josa'), ('중국', 'Noun'), ('과', 'Josa'), ('달라', 'Noun'), ('한자', 'Noun'), ('와', 'Josa'), ('서로', 'Noun'), ('통', 'Noun'), ('하지', 'Verb'), ('아니하므로', 'Adjective'), (',', 'Punctuation'), ('우매', 'Noun'), ('한', 'Josa'), ('백성', 'Noun'), ('들', 'Suffix'), ('이', 'Josa'), ('말', 'Noun'), ('하고', 'Josa'), ('싶은', 'Verb'), ('것', 'Noun'), ('이', 'Josa'), ('있어도', 'Adjective'), ('마침내', 'Noun'), ('제', 'Noun'), ('뜻', 'Noun'), ('을', 'Josa'), ('잘', 'Verb'), ('표현', 'Noun'), ('하지', 'Verb'), ('못', 'VerbPrefix'), ('하는', 'Verb'), ('사람', 'Noun'), ('이', 'Josa'), ('많다', 'Adjective'), ('.', 'Punctuation'), ('내', 'Noun'), ('이를', 'Verb'), ('딱하게', 'Adjective'), ('여기어', 'Verb'), ('새로', 'Adjective'), ('스물', 'Noun'), ('여덟', 'Noun'), ('자를', 'Verb'), ('만들었으니', 'Verb'), (',', 'Punctuation'), ('사람', 'Noun'), ('들', 'Suffix'), ('로', 'Josa'), ('하여금', 'Adverb'), ('쉬', 'Noun'), ('익히어', 'Verb'), ('날', 'Noun'), ('마다', 'Josa'), ('쓰는', 'Verb'), ('데', 'Noun'), ('편하게', 'Adjective'), ('할', 'Verb'), ('뿐', 'Noun'), ('이다', 'Josa'), ('.', 'Punctuation')]
[Komoran pos 함수]
[('나랏말이', 'NA'), ('중국', 'NNP'), ('과', 'JC'), ('다르', 'VA'), ('아', 'EC'), ('한자', 'NNG'), ('와', 'JC'), ('서로', 'MAG'), ('통하', 'VV'), ('지', 'EC'), ('아니하', 'VX'), ('므로', 'EC'), (',', 'SP'), ('우매', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETM'), ('백성', 'NNG'), ('들', 'XSN'), ('이', 'JKS'), ('말', 'NNG'), ('하', 'XSV'), ('고', 'EC'), ('싶', 'VX'), ('은', 'ETM'), ('것', 'NNB'), ('이', 'JKS'), ('있', 'VV'), ('어도', 'EC'), ('마침내', 'MAG'), ('제', 'XPN'), ('뜻', 'NNG'), ('을', 'JKO'), ('잘', 'MAG'), ('표현', 'NNG'), ('하', 'XSV'), ('지', 'EC'), ('못하', 'VX'), ('는', 'ETM'), ('사람', 'NNG'), ('이', 'JKS'), ('많', 'VA'), ('다', 'EF'), ('.', 'SF'), ('내', 'NP'), ('이', 'NP'), ('를', 'JKO'), ('딱하', 'VA'), ('게', 'EC'), ('여기', 'VV'), ('어', 'EC'), ('새로', 'MAG'), ('스물', 'NR'), ('여덟', 'NR'), ('자', 'NNB'), ('를', 'JKO'), ('만들', 'VV'), ('었', 'EP'), ('으니', 'EC'), (',', 'SP'), ('사람', 'NNG'), ('들', 'XSN'), ('로', 'JKB'), ('하여금', 'MAG'), ('쉬', 'MAG'), ('익히', 'VV'), ('어', 'EC'), ('날', 'NNG'), ('마다', 'JX'), ('쓰', 'VV'), ('는', 'ETM'), ('데', 'NNB'), ('편하', 'VA'), ('게', 'EC'), ('하', 'VV'), ('ㄹ', 'ETM'), ('뿐', 'NNB'), ('이', 'VCP'), ('다', 'EF'), ('.', 'SF')]
[Hannanum pos 함수]
[('나랏말', 'N'), ('이', 'J'), ('중국', 'N'), ('과', 'J'), ('다르', 'P'), ('아', 'E'), ('하', 'P'), ('ㄴ', 'E'), ('자', 'N'), ('와', 'J'), ('서로', 'M'), ('통하', 'P'), ('지', 'E'), ('아니하', 'P'), ('므로', 'E'), (',', 'S'), ('우매', 'N'), ('하', 'X'), ('ㄴ', 'E'), ('백성들', 'N'), ('이', 'J'), ('말', 'N'), ('하고', 'J'), ('싶', 'P'), ('은', 'E'), ('것', 'N'), ('이', 'J'), ('있', 'P'), ('어도', 'E'), ('마침내', 'M'), ('저', 'N'), ('의', 'J'), ('뜻', 'N'), ('을', 'J'), ('잘', 'M'), ('표현', 'N'), ('하', 'X'), ('지', 'E'), ('못하', 'P'), ('는', 'E'), ('사람', 'N'), ('이', 'J'), ('많', 'P'), ('다', 'E'), ('.', 'S'), ('내', 'N'), ('이', 'N'), ('를', 'J'), ('딱하', 'P'), ('게', 'E'), ('여기', 'N'), ('이', 'J'), ('어', 'E'), ('새로', 'M'), ('스물여덟', 'N'), ('자', 'N'), ('를', 'J'), ('만들', 'P'), ('었으니', 'E'), (',', 'S'), ('사람들', 'N'), ('로', 'J'), ('하여금', 'M'), ('쉬', 'M'), ('익히', 'P'), ('어', 'E'), ('날마다', 'M'), ('쓰', 'P'), ('는', 'E'), ('데', 'N'), ('편하', 'P'), ('게', 'E'), ('하', 'P'), ('ㄹ', 'E'), ('뿐', 'N'), ('이', 'J'), ('다', 'E'), ('.', 'S')]

품사 태깅은 분석기별로 차이가 있으니 자세한 내용은 아래의 링크를 참고해 주세요:)

구글스프레드시트링크

 

Korean POS tags comparison chart

chart Not provided in KoNLPy,Provided in KoNLPy Sejong project (ntags=42),Sim Gwangsub project (ntags=26),Twitter Korean Text (ntags=19),Komoran (ntags=42),Mecab-ko (ntags=43),Kkma (ntags=10),Kkma (ntags=30),Kkma (ntags=56),Hannanum (ntags=9),Hannanum (nta

docs.google.com

전체 코드
####한국어 형태소 분석기####
from konlpy.tag import Kkma, Komoran, Okt, Hannanum #Mecab은 윈도우에서 작동 불가능
okt = Okt()
kkma = Kkma()
komoran = Komoran()
hannanum = Hannanum()

text = '나랏말이 중국과 달라 한자와 서로 통하지 아니하므로, \
    우매한 백성들이 말하고 싶은 것이 있어도 마침내 제 뜻을 잘 표현하지 못하는 사람이 많다.\
    내 이를 딱하게 여기어 새로 스물여덟 자를 만들었으니, \
    사람들로 하여금 쉬 익히어 날마다 쓰는 데 편하게 할 뿐이다.'

#### .morphs()함수: 텍스트를 형태소 단위로 나누어준다.####
print("[Kkma morphs 함수]")
print(kkma.morphs(text))
print("[Okt 함수]")
print(okt.morphs(text))
print("[Komoran 함수]")
print(komoran.morphs(text))
print("[Hannanum 함수]")
print(hannanum.morphs(text))

##### stem: 각 단어에서 어간 추출 #####
print("[Okt 함수: stem사용하여 어간 추출]")
print(okt.morphs(text, stem= True))

#### .nouns()함수: 명사를 추출 ####
print("[Kkma nouns 함수]")
print(kkma.nouns(text))
print("[OKt nouns 함수]")
print(okt.nouns(text))
print("[Komoran nouns 함수]")
print(komoran.nouns(text))
print("[Hannanum nouns 함수]")
print(hannanum.nouns(text))

#### .phrases()함수: 어절 추출 ####
print("[Okt phrases 함수]")
print(okt.phrases(text))

#### .pos()함수: 품사 태깅 #### 
print("[Kkma pos 함수]")
print(kkma.pos(text)) #join=True는 형태소와 품사를 붙여서 리스트화
print("[Okt pos 함수]")
print(okt.pos(text))
print("[Komoran pos 함수]")
print(komoran.pos(text))
print("[Hannanum pos 함수]")
print(hannanum.pos(text))
코드 파일

nlp_konlpy.py
0.00MB

참고 자료

 

마무리

오늘 konlpy 분석기에 대해 알아보았는데요, 다음 시간에는 nltk를 자세히알아 보려고 합니다.

포스팅 관련 알고 싶은 내용이나 질문이 있다면 댓글 남겨주세요(^人^)

반응형
반응형

안녕하세요!

오늘은 konlpy(한국어 형태소 분석기)와 nltk(영어 분석기)를 이용하여

텍스트에 어떤 단어가 많이 나왔는지 알아보도록 하겠습니다.

1. 설치

빈도 분석을 하기 위해서는 konlpy와 nltk를 미리 설치해야 import 하여 사용할 수 있습니다.

- Konlpy설치: KoNLPy 공식문서 참고

 

설치하기 — KoNLPy 0.5.2 documentation

우분투 Supported: Xenial(16.04.3 LTS), Bionic(18.04.3 LTS), Disco(19.04), Eoan(19.10) Install dependencies # Install Java 1.8 or up $ sudo apt-get install g++ openjdk-8-jdk python3-dev python3-pip curl Install KoNLPy $ python3 -m pip install --upgrade p

konlpy.org

- nltk 설치

pip install nltk

위의 명령어를 프롬프트에서 실행해 주세요.

2. 데이터 준비

설치를 했으면 분석을 하기 위한 데이터가 필요하겠죠?

분석을 위한 영어, 한국어 텍스트를 각각 준비해 줍니다.

저는 한국어 텍스트로는 '황순원 - 소나기'를

소나기

영어 텍스트는 스티브 잡스의 유명한 졸업 연설문을 준비하였습니다.

스티브 잡스 연설문

 

스티브잡스 스탠포드 연설문 mp3 및 steve jobs 연설 스크립트 - 영어천재가 된 홍대리

영어천재가 된 홍대리에서 또 한가지 나왔던 공부하기 좋은 영어회화mp3중 하나가 스티브 잡스 스탠포드 연...

blog.naver.com

 다른 분석하고 싶은 텍스트가 있으면 준비하셔서 진행하시면 됩니다. ㅎㅎ

3. 텍스트 읽어오기
####텍스트 읽어오기####
##한국어 텍스트##
f = open("./소나기.txt",'rt',encoding='utf-8')
lines = f.readlines()
line = []
for i in range(len(lines)):
    line.append(lines[i])
f.close()

print(line)
##영어 텍스트##
f = open("./stevejobs.txt",'rt',encoding='utf-8')
lines2 = f.readlines()
line2 = []
for i in range(len(lines2)):
    line2.append(lines2[i])
f.close()

print(line2)

출력:

한국어(line)

영어(line 2)

4. 텍스트에서 특수문자 지워주기

텍스트를 보면, "", \n,...... 한자 등과 같은 텍스트 분석 시 필요 없는 부분들이 있습니다.

이런 특수문자 및 기호를 지워 깔끔한 데이터만 남겨 주도록 하겠습니다.

###특수문자 제거하기###
##한국어##
import re
compile = re.compile("[^ ㄱ-ㅣ가-힣]+")
for i in range(len(line)):

    a = compile.sub("",line[i])
    line[i] = a
print(line)

출력:

영어를 다듬을 때는 대소문자를 통일시켜줘야 합니다.

Apple, apple 이렇게 있을 때 파이썬에서는 각각 단어로 인식하기 때문에

lower()을 이용해 소문자로 통일시켜 주겠습니다. 대문자로 통일하고 싶을 때는. upper()을 사용하면 됩니다.

##영어##
compile = re.compile("\W+")
for i in range(len(line2)):

    a = compile.sub(" ",line2[i])
    line2[i] = a.lower()
print(line2)

출력:

5. 불용어 제거하기

불용어는 사용하지 않는 단어로 특수문자와 같이 분석 시 필요 없는 단어를 말합니다.

이었다, 것이다 등등의 불용어를 지워보도록 하겠습니다.

###불용어 제거하기###
##한국어##
stop_word = ["허 참 세상일도", "내면서", "것이다"] #사용하지 않을 단어 또는 문장 추가
line = [i for i in line if i not in stop_word]

영어는 불용어(stopwords)를 모아 놓은 리스트가 있는데 그것을 다운로드하여 제거해 보도록 하겠습니다.

nltk import 후 한 번만 실행해 주시어 다운로드하고 주석처리해주시면 됩니다.

다만 지금 제가 사용하고 있는 텍스트는 문장 단위로 구성되어 있어 적용이 어려운데,

추후 단어 리스트로 분석한다면 아래와 같이 사용하시면 됩니다.

##영어##
import nltk
##처음 한번만 실행 후 주석처리##
nltk.download('all')
nltk.download('wordnet')
nltk.download('stopwords')
##############################
from nltk.corpus import stopwords
stop_word_eng = set(stopwords.words('english'))
line2 = [i for i in line2 if i not in stop_word_eng]
6. 품사 분석 및 어근이 같은 부분 동일화, 토큰 화하기

텍스트 리스트가 문장으로 되어 형태소 분석으로 품사를 나누어서 단어 빈도수를 세어 주도록 하겠습니다.

영어는 문장을 토큰화 한 다음 어근 동일화 후에 영어 불용어 처리를해 줍니다.

어근 동일화란 eat- ate- eaten 과같이

의미가 같지만 모양이 조금씩 다른 단어들을 컴퓨터가 같은 단어로 인식할 수 있도록

전 처리하는 과정입니다.

그리고 추후 포스팅에 stemming, Part-Of-Speech와 관련한 설명을 하도록 하겠으니 모르셔도 걱정 마세요ㅎㅎ

오늘은 이런 식으로 분석하는구나 라고 감을 잡으시면 됩니다.

한국어는 Okt를 사용하여 명사만 뽑아 주도록 하겠습니다.

###문장분석###
##한국어##
from konlpy.tag import Okt
okt = Okt()
result =[]
result = [okt.nouns(i) for i in line] #명사만 추출
final_result= [r for i in result for r in i]
print(final_result)

출력:

영어는 RegexpTokenizer를 이용해 토큰화 해주도록 하겠습니다.

그 후, PorterStemmer를 이용해 어근 동일화를 해 줍니다.

##영어##
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem.porter import PorterStemmer
ps_stemmer = PorterStemmer()
token = RegexpTokenizer('[\w]+')
result2 = [token.tokenize(i) for i in line2]
middle_result2= [r for i in result2 for r in i]
final_result2 = [ps_stemmer.stem(i) for i in middle_result2 if not i in stop_word_eng] # 불용어 제거
print(final_result2)

출력:

 

+ 6.1 어간 추출 대신 표제어 추출(lemmatization)을 사용했을 때(영어)
##영어##
### 표제어 추출 사용 시 ###
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
token = RegexpTokenizer('[\w]+')
result_pre_lem = [token.tokenize(i) for i in line2]
middle_pre_lem= [r for i in result_pre_lem for r in i]
final_lem = [lemmatizer.lemmatize(i) for i in middle_pre_lem if not i in stop_word_eng] # 불용어 제거
print(final_lem)

 

7. 단어 수 세기

이렇게 다듬은 단어들을 pandas로 같은 단어를 세어

Series로 텍스트에서 제일 많이 나온 단어 10개만 반환하여 보도록 하겠습니다.

###텍스트에서 많이 나온 단어###
import pandas as pd
##한국어##
korean = pd.Series(final_result).value_counts().head(10)
print("한국어 top 10")
print(korean)

##영어##
english = pd.Series(final_result2).value_counts().head(10)
print("English top 10")
print(english)

출력:

한국어

영어

이렇게 많이 나온 단어들을 확인할 수 있습니다.

+ 7.1 lemmatization 사용 시 빈도 순위
###텍스트에서 많이 나온 단어###
###표제어 추출 시#####
import pandas as pd
##영어##
english = pd.Series(final_lem).value_counts().head(10)
print("English top 10")
english

전체 코드
####텍스트 읽어오기####
##한국어 텍스트##
f = open("./소나기.txt",'rt',encoding='utf-8')
lines = f.readlines()
line = []
for i in range(len(lines)):
    line.append(lines[i])
f.close()

#print(line)
##영어 텍스트##
f = open("./stevejobs.txt",'rt',encoding='utf-8')
lines2 = f.readlines()
line2 = []
for i in range(len(lines2)):
    line2.append(lines2[i])
f.close()

#print(line2)

###특수문자 제거하기###
##한국어##
import re
compile = re.compile("[^ ㄱ-ㅣ가-힣]+")
for i in range(len(line)):

    a = compile.sub("",line[i])
    line[i] = a
#print(line)

##영어##
compile = re.compile("\W+")
for i in range(len(line2)):

    a = compile.sub(" ",line2[i])
    line2[i] = a.lower()
#print(line2)

###불용어 제거하기###
##한국어##
stop_word = ["허 참 세상일도", "내면서", "것이다"] #사용하지 않을 단어 또는 문장 추가
line = [i for i in line if i not in stop_word]
#print(line)

##영어##
import nltk
##처음 한번만 실행 후 주석처리##
"""nltk.download('all')
nltk.download('wordnet')
nltk.download('stopwords')"""
##############################
from nltk.corpus import stopwords
stop_word_eng = set(stopwords.words('english'))
line2 = [i for i in line2 if i not in stop_word_eng]

###문장분석###
##한국어##
from konlpy.tag import Okt
okt = Okt()
result =[]
result = [okt.nouns(i) for i in line] #명사만 추출
final_result= [r for i in result for r in i]
#print(final_result)

##영어##
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem.porter import PorterStemmer
ps_stemmer = PorterStemmer()
token = RegexpTokenizer('[\w]+')
result2 = [token.tokenize(i) for i in line2]
middle_result2= [r for i in result2 for r in i]
final_result2 = [ps_stemmer.stem(i) for i in middle_result2 if not i in stop_word_eng] # 불용어 제거
#print(final_result2)

###텍스트에서 많이 나온 단어###
import pandas as pd
##한국어##
korean = pd.Series(final_result).value_counts().head(10)
print("한국어 top 10")
print(korean)

##영어##
english = pd.Series(final_result2).value_counts().head(10)
print("English top 10")
print(english)


#########영어 표제어 추출 시 ###########
##영어##
### 표제어 추출 사용 시 ###
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
token = RegexpTokenizer('[\w]+')
result_pre_lem = [token.tokenize(i) for i in line2]
middle_pre_lem= [r for i in result_pre_lem for r in i]
final_lem = [lemmatizer.lemmatize(i) for i in middle_pre_lem if not i in stop_word_eng] # 불용어 제거
#print(final_lem)

###텍스트에서 많이 나온 단어###
###표제어 추출 시#####
import pandas as pd
##영어##
english2 = pd.Series(final_lem).value_counts().head(10)
print("English top 10")
english2

 

코드 파일

nlp_counter.py
0.00MB

 

+ 영어분석만 있는 코드

nlp_counter_eng.ipynb
0.08MB

참고자료

1. 책 잡아라! 텍스트마이닝 with 파이썬(지금 바로 할 수 있는 데이터 추출과 분석) -서대호

 

2. 어간 추출과 표제어 추출

 

03) 어간 추출(Stemming) and 표제어 추출(Lemmatization)

정규화 기법 중 코퍼스에 있는 단어의 개수를 줄일 수 있는 기법인 표제어 추출(lemmatization)과 어간 추출(stemming)의 개념에 대해서 알아봅니다. 또한 이 ...

wikidocs.net

마무리

오늘 이렇게 자연어 처리 텍스트 빈도 분석을 해 보았는데요.

텍스트 양이 더 많고 불용어 처리를 섬세히 해주면 더 좋은 결과가 나올 것 같습니다 ㅎㅎ

좋아하는 가수의 가사나 이런 걸로도 분석해도 재밌을 것 같네요.

다른 아이디어가 있으면 댓글로 남겨주세요 :)

반응형
반응형

안녕하세요!

오늘은 저번에 했던 용산구 CCTV위치 시각화에 이어서 가로등 위치를 추가하고 클러스터링 해보겠습니다.

CCTV위치 시각화 관련 포스팅은 아래를 참고해 주세요.

 

[python] folium을 이용하여 CCTV 위치 시각화하기

안녕하세요! ㅎㅎ 오늘을 folium을 이용해서 지리정보 시각화를 간단히 해 보려고 합니다. 그럼 시작하겠습니다! Preview step1. 데이터 준비하기 오늘 사용할 데이터는 서울 열린 데이터 광장의 '용

wonhwa.tistory.com

 

Preview

Preview

step1. 데이터 준비하기

용산구의 CCTV, 가로등 위치를 시각화 해야 되니까 두 개의 데이터 파일이 필요합니다.

1. 용산구 CCTV 파일

서울시 열린 데이터

 

열린데이터광장 메인

데이터분류,데이터검색,데이터활용

data.seoul.go.kr

2. 용산구 가로등 현황 파일(용산구)

전국 보안등 정보 표준데이터

 

전국보안등정보표준데이터

보안등정보(보안등위치, 설치개수 등)를 제공합니다. 공공데이터 개방 표준데이터 속성정보(표현형식/단위 등)는 [공공데이터 개방 표준]고시를 참고하시기 바랍니다.(정보공유>자료실>법령(고

www.data.go.kr

가로등 파일은 서울 검색 후 용산구로 다운 받으시면 됩니다.

 

step2. cctv와 가로등 위치데이터 추출하기

위치를 시각화하기위해 용산구 cctv, 가로등의 위, 경도 데이터를 모두 추출해 주도록 하겠습니다.

cctv는 전 게시물과 동일하므로 코드를 첨부하도록 하겠습니다.

###CCTV위치 꺼내기#### 
# CSV 파일 열기
import pandas as pd
file = r'C:\파일위치\yongsan_CCTV.csv'
file = file.replace('\\','//')
#print(file)
cctv_csv = pd.read_csv(file,encoding='cp949')
print(cctv_csv.head(5))

# 데이터프레임 NaN 값 대체
cctv_csv = cctv_csv.fillna(0.0)
print(cctv_csv.head())

# x좌표(위도),y좌표(경도) 리스트로 만들기
x = []
y = []
for i in range(len(cctv_csv['WGS x좌표'])):
    if cctv_csv['WGS x좌표'][i] == 0.0 or cctv_csv['WGS y좌표'][i] == 0.0:
        pass
    else:

        x.append(cctv_csv['WGS x좌표'][i])
        y.append(cctv_csv['WGS y좌표'][i])
print('x갯수: ',len(x))
print('y갯수: ',len(y))

이제 가로등 위치를 꺼내보도록 하겠습니다.

가로등도 cctv와 마찬가지로 데이터 확인 후 필요정보를 뽑아보도록 하겠습니다.

####가로등 파일 열기#####
# CSV 파일 열기
import pandas as pd
file = r'C:\파일위치\서울특별시_용산구_보안등정보.csv'
file = file.replace('\\','//')
#print(file)
street_csv = pd.read_csv(file,encoding='cp949')
print(street_csv.head())

출력:

여기서 필요한 정보는 위도(x) 경도(y), 그리고 나중에 위치 마킹할 때 이름을 달아주기 위해 보안등 위치명까지 뽑아 보도록 하겠습니다.

NaN이 있는 곳은 0.0으로 대체 후 , 위경도에 0.0이 있으면 그 곳은 제외하는 방식으로 값을 저장해 주도록 하겠습니다.

# 데이터프레임 NaN 값 대체
street_csv = street_csv.fillna(0.0)
print(street_csv.head())

# x좌표(위도),y좌표(경도), 이름 리스트로 만들기
x1 = []
y1 = []
name = []
for i in range(len(street_csv['위도'])):
    if street_csv['위도'][i] == 0.0 or street_csv['경도'][i] == 0.0:
        pass
    else:
        name.append(street_csv['보안등위치명'][i])
        x1.append(street_csv['위도'][i])
        y1.append(street_csv['경도'][i])
print('이름갯수: ',len(name))
print('x갯수: ',len(x1))
print('y갯수: ',len(y1))

출력:

가로등 수가 cctv 수보다 훨씬 많습니다.

 

step3. 지도를 만들고 그 위에 위치 표시하기

이제 필요한 데이터 준비는 다 되었으니 시각화해 보도록 하겠습니다.

지도를 불러오고, 그 위에 용산구 geojson파일로 구역을 눈에 들어오도록 시각화 해보겠습니다.

용산구 geojson 파일은 제가 미리 준비해 놓았으니 아래의 파일을 다운받아 사용해 주시면 됩니다:)

yongsan.zip.geojson
0.04MB

######지도 만들기#####
import folium
import folium.plugins as plug
import json

#map 만들기
map_osm = folium.Map(location=[37.538821, 126.98368841130002],zoom_start=14)
#geojson파일 오픈
file_name= r'C:\파일위치\yongsan.zip.geojson'
file_name = file_name.replace('\\','/')
with open(file_name, 'rt') as f:
    geo = json.load(f)
    f.close()
folium.GeoJson(geo, name='YongSan').add_to(map_osm)
map_osm

이렇게 용산구 지역에 표시가 되었습니다.ㅎㅎ

다음으로 cctv랑 가로등의 위치를 찍고 클러스터링 해 보도록 하겠습니다.

###가로등, cctv 위치 표시및 클러스터링### 
import folium.plugins as plug
marker_cluster = plug.MarkerCluster().add_to(map_osm)

for i in range(len(x)):

    folium.Marker([x[i],y[i]], popup='용산CCTV_%d'%i, icon=folium.Icon(color='red', icon='ok-circle')).add_to(marker_cluster)

for i in range(len(x1)):
    
    folium.Marker([x1[i],y1[i]], popup= name[i], icon=folium.Icon(color='orange', icon='star')).add_to(marker_cluster)

지도 위에 표시하는 아이콘은 모양을 설정할 수 있는데요 icon 종류는 아래의 링크를 참고해주세요.

glyphicons

 

Components · Bootstrap

Extend form controls by adding text or buttons before, after, or on both sides of any text-based . Use .input-group with an .input-group-addon or .input-group-btn to prepend or append elements to a single .form-control. Textual s only Avoid using elements

getbootstrap.com

마크 Icon 종류

만약 음표 아이콘을 쓰고 싶다면 파라미터에 icon=folium.Icon(icon=music) 이렇게 작성하면 됩니다.

다른 아이콘도 glyphicon glyphicon- 뒤에 써져 있는 아이콘이름을 입력해 주면 적용이 됩니다ㅎㅎ 

#map저장
map_osm.save('YONGSAN.html')

결과물: 

자 그럼 이렇게 완성이 됩니다 ㅎㅎ

스크롤을 위로 올리면 확대가 되면서 원이 더 많이 생기고 그중 하나를 클릭해 보면,

아까 만든 cctv,가로등 마크와 이름을 확인할 수 있습니다.

별모양은 가로등, cctv는 빨간 마크입니다.

전체 코드
####CCTV#####
# CSV 파일 열기
import pandas as pd
file = r'C:\파일위치\yongsan_CCTV.csv'
file = file.replace('\\','//')
#print(file)
cctv_csv = pd.read_csv(file,encoding='cp949')
print(cctv_csv.head(5))

# 데이터프레임 NaN 값 대체
cctv_csv = cctv_csv.fillna(0.0)
print(cctv_csv.head())

# x좌표(위도),y좌표(경도) 리스트로 만들기
x = []
y = []
for i in range(len(cctv_csv['WGS x좌표'])):
    if cctv_csv['WGS x좌표'][i] == 0.0 or cctv_csv['WGS y좌표'][i] == 0.0:
        pass
    else:

        x.append(cctv_csv['WGS x좌표'][i])
        y.append(cctv_csv['WGS y좌표'][i])
print('x갯수: ',len(x))
print('y갯수: ',len(y))

#####가로등######
# CSV 파일 열기
import pandas as pd
file = r'C:\Users\user\Desktop\web_AI\python_code\서울특별시_용산구_보안등정보.csv'
file = file.replace('\\','//')
#print(file)
street_csv = pd.read_csv(file,encoding='cp949')
print(street_csv.head())

# 데이터프레임 NaN 값 대체
street_csv = street_csv.fillna(0.0)
print(street_csv.head())

# x좌표(위도),y좌표(경도), 이름 리스트로 만들기
x1 = []
y1 = []
name = []
for i in range(len(street_csv['위도'])):
    if street_csv['위도'][i] == 0.0 or street_csv['경도'][i] == 0.0:
        pass
    else:
        name.append(street_csv['보안등위치명'][i])
        x1.append(street_csv['위도'][i])
        y1.append(street_csv['경도'][i])
print('이름갯수: ',len(name))
print('x갯수: ',len(x1))
print('y갯수: ',len(y1))

######지도생성######
import folium
import folium.plugins as plug
import json
#map 만들기
map_osm = folium.Map(location=[37.538821, 126.98368841130002],zoom_start=14)
#클러스터추가
marker_cluster = plug.MarkerCluster().add_to(map_osm)
#geojson파일 오픈
file_name= r'C:\Users\user\Downloads\yongsan.zip.geojson'
file_name = file_name.replace('\\','/')
with open(file_name, 'rt') as f:
    geo = json.load(f)
    f.close()
folium.GeoJson(geo, name='YongSan').add_to(map_osm)

for i in range(len(x)):

    folium.Marker([x[i],y[i]], popup='용산CCTV_%d'%i, icon=folium.Icon(color='red', icon='ok-circle')).add_to(marker_cluster)

for i in range(len(x1)):
    folium.Marker([x1[i],y1[i]], popup= name[i], icon=folium.Icon(color='orange', icon='star')).add_to(marker_cluster)

#map저장
map_osm.save('YONGSAN.html')
코드 파일

깃허브

 

GitHub - ElenaLim/Visualizations: This repository is for python visualizations, enjoy🤟

This repository is for python visualizations, enjoy🤟 - GitHub - ElenaLim/Visualizations: This repository is for python visualizations, enjoy🤟

github.com

 

마무리

오늘은 이렇게 geojson과 클러스터링까지 하여 시각화를 해보았습니다 ㅎㅎ

이런 위치정보를 가지고 안전한 길찾기 서비스를 해도 좋을 것 같네요.

다른 좋은 아이디어가 있으면 댓글로 공유 부탁드려요 ㅎㅎ

반응형

+ Recent posts