4.2. Feature extraction — scikit-learn 0.17.1 documentation 의 글 중 일부를 번역해 놓는다.
Feature extraction
Feature extraction 은 text 또는 image 같은 임의의 data(arbitrary data) 를 machine learning 에 쓸수있는 "숫자와 관련된 feature 들(numerical features)"로 변환하는 특징을 갖는다. [ref. 1]Text feature extraction
The Bag of Words representation
text content 에서 numerical feature 를 추출하기 위해 scikit-learn 에서 다음 3개의 utility 를 제공한다.- tokenizing : 이건 문자열을 token 들로 쪼개는 것이다.
- counting : 각 문서(document) 의 토큰이 몇번 나왔는지를 세는 것
- normalizing and weighting with diminishing importance tokens that occur in the majority of samples / documents.
tokenizing, counting, nomalizing 을 하는 이 특정 전략을 bag of words 라 한다.
이 전략에서 feature 와 sample 의 정의는 아래와 같다.
- feature : 여기서 feature 는 "각각의 token의 발생 빈도" 이다.
- sample : 모든 token 의 빈도들을 갖고 있는 vector 는 다변수의 sample 로 여겨진다.
"Bag of words" 표현(representation) 또는 "Bag of n-grams" 표현 이라 얘기한다.
여기서 document 는 word 의 occurrence로만 표현된다. 단어의 상대적인 위치 정보는 무시한다.
...
Limitations of the Bag of Words representation
자세한 이야기는 link 를 이용하자. 대략적으로 Bag of words representation 의 한계를 이야기하면, 같은 의미의 단어인데,- 철자가 틀렸거나,
- 복수형등으로 조금 변형된 상태
에서도 다른 단어로 처리하게 되는 것이다. 이런 요소로 classification 의 정확도가 떨어진다. 이런 것을 극복하기 위해 "n-grams" 를 사용하게 된다.
이건 단어 하나를 그대로 하나의 token 으로 인식해서 판별하는 것(n-gam 0)이 아니라, 그것을 여러개의 combination 을 만든다. 예를 들어,
"A T T C A" 라는 문장이 있다면, 이것을 unigram(n-gram 0) 으로 분할 하면,
A, T, T, C, A
로 나눠서 검사를 하는데, bigram(n-gram 1) 로 분할하면,
AT, TT, TC, CA
로 나눠서 이것들을 검사하게 된다.
이렇게 n-gram 을 vectorizer 의 parameter 로 지정해 줄 수 있다. 자세한 것은 link 를 참고하자.
Vectorizing a large text corpus with the hashing trick
이제까지 언급한 vectorization 방법들(CounterVectorizer, TfidfVectorizer 등등) 은 메모리 안에서 token 들을 "정수 feature의 인덱스"에 mapping 했다. 근데 이게 큰 dataset 을 처리할 때 문제가 있다.- 더 큰 크기의 문서를 다루면, 많은 더 많은 단어들이 사용되고 이게 또 메모리를 더 많이 사용하게 된다.
- fitting 은 원본 dataset 에 비례하는 크기의 중간 데이터 구조에 대한 메모리 할당을 필요로 한다.
- word-mapping 을 만드는 것은 dataset 를 전부 읽는 과정이 필요하다. 그래서 text classifier 를 특히 온라인 등의 환경에 맞우는 것은 불가능하다.
- 큰 vocabulary_ 를 가지고 vectorizers 를 pickling 과 un-pickling 하는 것은 매우 느릴 수 있다.(일반적으로 같은 크기의 NumPy array 같은 flat data structures 를 pickling / un-pickling 하는 것보다 훨씬 느리다.)
- vocabulary_ 속성은 공유되는 state 로 하고 "잘 만들어진 동기화 장벽(synchronization barrier)"를 이용해서 vectorization 작업을 concurrent 한 sub task 로 분리하는 것은 쉽지 않다.
token 문자열 을 feature index 에 mapping 하는 것은 각 token 의 첫 occurrence 의 순서에 달려있다. 그래서 공유되어야만 한다. 그런데 이것은 잠재적으로 councurrent worker들의 sequential variant 보다 더 느리게 만들정도로 성능에 해를 끼친다.
sklearn.feature_extraction.FeatureHasher class 에 구현되어 있는 hashing trick (Feature hashing) 과 CountVectorizer 의 text preprocessing, tokenization feature 들과 결합해서 이 한계를 극복할 수 있다.
Feature hasing
machine-learning 에서 feature hashing 은 hashing trick 으로 알려져 있다.빠르고, space 효율적인 feature 를 vetorize 하는 방법이다. 즉, 임의의 feature 들을 vector 안의 index 로 바꿔주는 작업이다.
hash function 를 feature 들에 적용한다. 그리고 그들의 hash 값들이 바로 index 로 이용된다. 중간에 hash 와 array 의 index 를 다시 mapping 하는 부분을 두지 않는다.
보통 document 가 있으면 이것을 word 로 쪼개서 matrix 를 만들게 된다. 그러면 하나의 row 가 하나의 document 를 뜻하게 되고, column 이 한개의 word 를 뜻하게 된다. 이 경우에 word 에 해당하는 index 가 무엇인지를 알려주기 위해 index table 이 필요하다. 일반적으로 learning time 또는 그 전에 training set 의 vocabulary 에 대한 dictionary 를 하나 만들게 된다.
1st doc : Nam is working
2nd doc : Nam is not working
Nam is working not 1st doc. 1 1 1 0 2nd doc. 1 1 1 1 dictionary = { 'Nam': 0, 'is': 1, 'working': 2, 'not': 3 }
value = matrix[1][dictionary['Nam']] | | | \/ value = matrix[1][hashFunc('Nam')]이것의 문제는 document 크기가 크거나, document 가 많아져서, training set 이 커지고, 그 안의 vocabulary 가 많아지면, dictionary 를 만들기 위해 더 많은 memory 가 필요하다.
이렇게 dictionary 를 만드는 대신에 hashing trick 을 이용하는 feature vectorizer 는 hash function 을 feature(여기선 word 가 되겠다.) 에 적용해서 "미리 정해진 길이의 vector" 를 만들 수 있다.
hash value 를 feature index 로 사용해서 그 index 에 있는 vector 값을 업데이트 한다.(hash value 가 vector size N 을 넘지 않게 하기 위해 mod N 을 해준다.)
이 경우에, collision 이 생길 수 있다. 이를 위해 또 다른 hash function을 제공한다.(그러나 이것으로 collision 이 해결되지는 않을 듯 한데....)
댓글 없음:
댓글 쓰기