프로그래밍/자연어처리

sklearn TF-IDF vectorizer 사용 예시

kugancity 2017. 2. 8. 15:36
반응형





Sklearn TfidfVectorizer 클래스 사용법 




TF-IDF vectorizer 는 문서를 tf-idf의 feature matrix로 변환하는 클래스입니다. 

문서에 CountVectorizer를 사용하고 TfidfTransformer를 사용한 것과 똑같은 결과를 가집니다. 




\text{idf}(t) = log{\frac{1 + n_d}{1+\text{df}(d,t)}} + 1,

where n_d is the total number of documents, and \text{df}(d,t) is the number of documents that contain term t. The resulting tf-idf vectors are then normalized by the Euclidean norm:

v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 +
v{_2}^2 + \dots + v{_n}^2}}.




여기서 feature는 문장의 토큰 단위로 

 아래 TfidfVectorizer함수의 analyzer, tokenizer, token_pattern, stop_words 

등의 분석 단계를 거쳐 나온 토큰들을  의미합니다. 


TfidfVectorizer 클래스 설명 문서 바로가기 


feature extraction 설명 문서 바로가기 




class sklearn.feature_extraction.text.TfidfVectorizer(input=u'content', encoding=u'utf-8', decode_error=u'strict', 


strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, analyzer=u'word', stop_words=None, 


token_pattern=u'(?u)\b\w\w+\b', ngram_range=(1, 1), max_df=1.0, min_df=1, max_features=None, vocabulary=None, 


binary=False, dtype=<type 'numpy.int64'>, norm=u'l2', use_idf=True, smooth_idf=True, sublinear_tf=False)




이 함수의 기본 토큰 패턴(token_pattern) 옵셥이 \w\w+ (두 letter 이상)임에 유의하세요. 

이걸 모르고 위키피디아를 기본 옵션으로 돌렸을 때

 single letter들이 토큰으로 나오지 않아 이리저리 찾아보는 삽질을 했었다는;


클래스 사용법은 간단합니다. 

한국어 위키피디아 문서로 클래스 함수들을 사용하는 예시를 작성하였으니 확인해봅시다. 



입력으로 넣었던 테스트 문장은 아래와 같습니다. 

한국어 위키에서 가져온 10 문장이고 mecab으로 이미 형태소 단위 토크나이징이 완료된 상태입니다. 


위키 문서 및 토크나이징 관련 이전 포스팅 바로가기



지미 카터

제임스 얼 " 지미 " 카터 주니어 ( , 1924 년 10 월 1 일 ~ ) 는 민주당 출신 미국 39 번 째 대통령 ( 1977 년 ~ 1981 년 ) 이 다 .

지미 카터 는 조지아 주 섬터 카운티 플 레인스 마을 에서 태어났 다 . 조지 아 공과 대학교 를 졸업 하 였 다 . 그 후 해군 에 들어가 전함 · 원자력 · 잠수함 의 승무>원 으로 일 하 였 다 . 1953 년 미국 해군 대위 로 예편 하 였 고 이후 땅콩 · 면화 등 을 가꿔 많 은 돈 을 벌 었 다 . 그 의 별명 이 " 땅콩 농부 " ( Peanut Farmer ) 로 알려졌 다 .


1962 년 조지아 주 상원 의원 선거 에서 낙선 하나 그 선거 가 부정 선거 였음을 입증 하 게 되 어 당선 되 고 , 1966 년 조지아 주 지사 선거 에 낙선 하 지만 1970 년 조지아 주 지사 를 역임 했 다 . 대통령 이 되 기 전 조지 아 주 상원 의원 을 두 번 연임 했으며 , 1971 년 부터 1975 년 까지 조지 아 지사 로 근무 했 다 . 조지 아 >주지사 로 지내 면서 , 미국 에 사 는 흑인 등 용법 을 내세웠 다 .
1976 년 대통령 선거 에 민주당 후보 로 출마 하 여 도덕주의 정책 으로 내세워 , 포드 를 누르 고 당선 되 었 다 .
카터 대통령 은 에너지 개발 을 촉구 했으나 공화 당 의 반대 로 무산 되 었 다 .
카터 는 이집트 와 이스라엘 을 조정 하 여 , 캠프 데이비드 에서 안와르 사다트 대통령 과 메나헴 베긴 수상 과 함께 중동 평화 를 위한 캠프 데이비드 협정 을 체결 했
 다 .
그러나 이것 은 공화 당 과 미국 의 유대인 단체 의 반발 을 일으켰 다 . 1979 년 백악관 에서 양국 간 의 평화 조약 으로 이끌 어 졌 다 . 또한 소련 과 제 2 차 전략 >무기 제한 협상 에 조인 했 다 .
카터 는 1970 년 대 후반 당시 대한민국 등 인권 후진국 의 국민 들 의 인권 을 지키 기 위해 노력 했으며 , 취임 이후 계속 해서 도덕 정치 를 내세웠 다 .
그러나 주 이란 미국 대사관 인질 사건 에서 인질 구출 실패 를 이유 로 1980 년 대통령 선거 에서 공화 당 의 로널드 레이건 후보 에게 져 결국 재선 에 실패 했 다 . >또한 임기 말기 에 터진 소련 의 아프가니스탄 침공 사건 으로 인해 1980 년 하계 올림픽 에 반공 국가 들 의 보이콧 을 내세웠 다 .
~






한글 파일이라 utf-8 설정을 해주고 파일을 읽어 리스트를 만듭니다. 


TfidfVectorizer 인스턴스를 만들고 fit_transform 메소드를 실행하면 

term-document matrix가 생성됩니다. 

참 쉽지요 ㅎㅎㅎ 





from sklearn.feature_extraction.text import TfidfVectorizer

import codecs



reload(sys)

sys.setdefaultencoding('utf-8')


filename =  sys.argv[1]

with codecs.open(filename, 'r', 'utf-8') as f:

    lines = f.readlines()


cv = TfidfVectorizer()

X = cv.fit_transform(lines)









참고로 TfidfVectorizer class method는 아래와 같습니다. 





fit_transform은 fit 과 transform 함수를 이어서 적용할 때와 결과는 동일한데 

좀 더 효율적으로 실행이 된다고 합니다. 


위 테스트 문장을 돌려본 결과를 확인해보겠습니다. 




print X.shape

(10, 158)


print X 


X

  (0, 129)      0.810839478277

  (0, 139)      0.585268605401

  (1, 129)      0.232816176569

  (1, 139)      0.168048057138

  (1, 116)      0.313038787048

  (1, 124)      0.313038787048

  (1, 1)        0.313038787048

  (1, 0)        0.313038787048

  (1, 59)       0.266111568208

  (1, 135)      0.313038787048

  (1, 58)       0.185888957728

  (1, 13)       0.313038787048

  (1, 39)       0.168048057138

  (1, 9)        0.313038787048

  (1, 12)       0.313038787048

...




X.shape를 보면 (10, 158)로 앞의 10은 문장 수, 뒤의 158은 feature 개수를 의미합니다. 

10개의 문장이 158 토큰으로 표현이 된 것입니다. 


fit_transform은 결과 매트릭스를 좀 더 압축된 형태로 보여줍니다. 

(0, 129)에서 0은 문서 인덱스, 128는 feature 인덱스, 숫자는 그 feature의 tf-idf 값을 의미합니다. 

첫번째 문장은 "지미 카터" 였으니 0 인덱스로 시작하는 값이 두 개가 있네요. 


압축된 형태로 보는 것이 아니라 전체 매트릭스를 보고 싶으면 toarray()를 사용하시면 됩니다. 








X_array = X.toarray()


print X_array 


[[ 0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.81083948  0.          0.          0.

   0.          0.          0.          0.          0.          0.

   0.58526861  0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.        ]


 [ 0.31303879  0.31303879  0.          0.          0.          0.          0.

   0.          0.          0.31303879  0.          0.          0.31303879

   0.31303879  0.          0.          0.          0.          0.          0.

   0.          0.          0.          0.          0.          0.          0.




그리고 각 term와 연결되어 있는 feature index를 확인하고 싶으면 

vocabulary_ 속성을 사용하면 됩니다. 

앞에 나온 지미의 feature index는 129네요. 






print cv.vocabulary_.get(u'지미')

129


print cv.vocabulary

{u'\ud130\uc9c4': 142, u'\ub300\uc704': 38, u'\uba74\ud654': 55, u'\ub2e8\uccb4': 34, u'\uc54c\ub824\uc84c': 80, u'1962': 3, u'\ub300\ud559\uad50': 40, u'\ud3ec\ub4dc': 144, u'\ub9c8\uc744': 51, u'\uad6d\uac00': 23, u'\uae4c\uc9c0': 27, u'\uc911\ub3d9': 126, u'peanut': 15, u'\uc870\uc778': 119, u'\ubc18\ubc1c': 62, u'\ubb34\uc0b0': 57, u'\uc870\uc57d': 118, u'\ud611\uc0c1': 152, u'farmer': 14, u'\uc8fc\uc9c0\uc0ac': 125, u'\uc81c\ud55c': 117, u'\ucde8\uc784': 136, u'\ud574\uc11c': 149, u'\uacf5\uacfc': 20, u'\ud3c9\ud654': 143, u'\ub4e4\uc5b4\uac00': 45, u'\ub178\ub825': 31, u'1953': 2, u'\uc720\ub300\uc778': 94, u'\uc774\uc9d1\ud2b8': 102, u'\ub300\ud1b5\ub839': 39, u'\uc804\ud568': 113, u'\uc120\uac70': 72, u'\uc5d0\uc11c': 84, u'\ub2f9\uc2dc': 36, u'1979': 10, u'\ub204\ub974': 33, u'\uc774\uc720': 101, u'\uc2e4\ud328': 77, u'\ubbf8\uad6d': 58, u'\uc218\uc0c1': 75, u'\uc2b9\ubb34\uc6d0': 76, u'\uc870\uc9c0': 121, u'1924': 1, u'\ub610\ud55c': 47, u'\ubd80\uc815': 67, u'\ubcf4\uc774\ucf67': 66, u'\ub370\uc774\ube44\ub4dc': 42, u'\uc0ac\ub2e4\ud2b8': 70, u'\uce74\ud130': 139, u'\ub099\uc120': 28, u'\uc5d0\ub108\uc9c0': 83, u'\ubb34\uae30': 56, u'\uc878\uc5c5': 123, u'\ucd09\uad6c': 133, u'\ud751\uc778': 157, u'\uc9c0\ubbf8': 129, u'\uc804\ub7b5': 112, u'\ubc18\uacf5': 60, u'\ubc31\uc545\uad00': 63, u'\uacc4\uc18d': 19, u'\ud558\uacc4': 145, u'\ud0dc\uc5b4\ub0ac': 141, u'\uc785\uc99d': 109, u'\uc0c1\uc6d0': 71, u'\ub85c\ub110\ub4dc': 50, u'\uc81c\uc784\uc2a4': 116, u'\uc758\uc6d0': 96, u'\uba54\ub098\ud5f4': 53, u'\uc774\ub780': 99, u'39': 13, u'\ub545\ucf69': 46, u'\ub18d\ubd80': 32, u'\ucea0\ud504': 140, u'\ub300\ud55c\ubbfc\uad6d': 41, u'\ucd9c\ub9c8': 134, u'\ud6c4\uc9c4\uad6d': 156, u'\uc870\uc9c0\uc544': 122, u'\uc5ed\uc784': 85, u'\uc8fc\ub2c8\uc5b4': 124, u'\uac00\uafd4': 16, u'\ub300\uc0ac\uad00': 37, u'\uc6a9\ubc95': 90, u'\uc774\ub04c': 98, u'\ud574\uad70': 148, u'\ub3c4\ub355': 43, u'\uc591\uad6d': 81, u'\uad6c\ucd9c': 22, u'\uc778\ud574': 106, u'\uc7ac\uc120': 111, u'1981': 12, u'\ub808\uc778\uc2a4': 49, u'\uc5f0\uc784': 86, u'\ub808\uc774\uac74': 48, u'\ucd9c\uc2e0': 135, u'\uba74\uc11c': 54, u'\uc870\uc815': 120, u'\ubc18\ub300': 61, u'\ud568\uaed8': 147, u'\uc704\ud55c': 92, u'\uc9c0\ub9cc': 128, u'\ud6c4\ubc18': 154, u'\ud611\uc815': 153, u'\uc774\uc2a4\ub77c\uc5d8': 100, u'10': 0, u'\uc778\uad8c': 104, u'\ubbfc\uc8fc\ub2f9': 59, u'\ud558\ub098': 146, u'\uc544\ud504\uac00\ub2c8\uc2a4\ud0c4': 78, u'\uc0ac\uac74': 69, u'1980': 11, u'\ud588\uc73c\ub098': 150, u'\ub3c4\ub355\uc8fc\uc758': 44, u'\uc704\ud574': 93, u'\uc73c\ub85c': 95, u'\uacb0\uad6d': 18, u'\uc7a0\uc218\ud568': 110, u'\uc6d0\uc790\ub825': 91, u'\ub2f9\uc120': 35, u'\ub9d0\uae30': 52, u'\uc18c\ub828': 74, u'\ub0b4\uc138\uc6e0': 30, u'1971': 6, u'\uc62c\ub9bc\ud53d': 89, u'\uadf8\ub7ec\ub098': 25, u'\uc774\ud6c4': 103, u'\ud588\uc73c\uba70': 151, u'\uc608\ud3b8': 88, u'\uc600\uc74c\uc744': 87, u'\uc815\uce58': 115, u'1966': 4, u'\uccb4\uacb0': 132, u'\ubd80\ud130': 68, u'\uc12c\ud130': 73, u'\uc815\ucc45': 114, u'\ud6c4\ubcf4': 155, u'\uac1c\ubc1c': 17, u'\uc784\uae30': 108, u'\uc548\uc640\ub974': 79, u'\uadfc\ubb34': 26, u'\uce74\uc6b4\ud2f0': 138, u'\uacf5\ud654': 21, u'\ubcc4\uba85': 65, u'\uc778\uc9c8': 105, u'\uce68\uacf5': 137, u'\ub0b4\uc138\uc6cc': 29, u'\ubca0\uae34': 64, u'\uc774\uac83': 97, u'\uc9c0\ud0a4': 131, u'1977': 9, u'1976': 8, u'1975': 7, u'\uc77c\uc73c\ucf30': 107, u'\uc9c0\uc0ac': 130, u'1970': 5, u'\uc9c0\ub0b4': 127, u'\uad6d\ubbfc': 24, u'\uc5d0\uac8c': 82}





get_feature_names라고 feature에 사용된 토큰들만 보여주는 함수도 있습니다. 

feature 리스트를 출력해보면 기본 토큰 패턴에 맞지 않는 기호들, single letter 인 토큰들은 

리스트에 없는 것을 확인할 수 있습니다.  





features = cv.get_feature_names()

for feature in features:

        print feature



10

1924

1953

1962

1966

1970

1971

1975

1976

1977

1979

1980

1981

39

farmer

peanut

가꿔

개발

결국

계속

공과

공화

구출

국가








마지막으로 속성들 중에서는 feature들의 idf 값만 따로 출력하는 _idf 속성도 있습니다. 



idf 벡터를 리턴하며 여기서 idf 값은 global term weight 입니다. 





idfs =  cv.idf_

print idfs.shape


(158,)


print idfs


[ 2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.29928298

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.01160091  2.70474809  2.70474809

  2.70474809  2.29928298  2.70474809  2.70474809  2.70474809  2.70474809

  2.01160091  2.70474809  2.70474809  2.70474809  2.70474809  2.29928298

  2.70474809  2.70474809  2.70474809  1.45198512  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.29928298

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  1.6061358   2.29928298

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.01160091  2.70474809  2.29928298  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  1.6061358   2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  1.78845736

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.29928298  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.29928298  2.29928298  2.70474809  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.01160091  2.70474809  2.70474809

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  1.45198512  2.70474809  2.70474809  2.70474809  2.29928298

  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809  2.70474809

  2.70474809  2.29928298  2.70474809  2.70474809  2.70474809  2.29928298

  2.70474809  2.70474809]





{word : column index in array}



참고: 


http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html


http://scikit-learn.org/stable/modules/feature_extraction.html


http://stackoverflow.com/questions/30976120/find-the-tf-idf-score-of-specific-words-in-documents-using-sklearn




728x90
반응형