TF-IDF(Term Frequency - Inverse Document Frequency) ๋?
- TF(๋จ์ด ๋น๋, term frequency)๋ ํน์ ํ ๋จ์ด๊ฐ
๋ฌธ์ ๋ด์ ์ผ๋ง๋ ์์ฃผ ๋ฑ์ฅํ๋์ง๋ฅผ ๋ํ๋ด๋ ๊ฐ
. ์ด ๊ฐ์ด๋์์๋ก ๋ฌธ์์์ ์ค์
ํ๋ค๊ณ ์๊ฐํ ์ ์๋ค. - ํ์ง๋ง ํ๋์ ๋ฌธ์์์ ๋ง์ด ๋์ค์ง ์๊ณ
๋ค๋ฅธ ๋ฌธ์์์ ์์ฃผ ๋ฑ์ฅํ๋ฉด ๋จ์ด์ ์ค์๋๋ ๋ฎ์์ง๋ค
. - DF(๋ฌธ์ ๋น๋, document frequency)๋ผ๊ณ ํ๋ฉฐ, ์ด ๊ฐ์ ์ญ์๋ฅผ IDF(์ญ๋ฌธ์ ๋น๋, inverse document frequency)๋ผ๊ณ ํ๋ค.
- TF-IDF๋ TF์ IDF๋ฅผ ๊ณฑํ ๊ฐ์ผ๋ก ์ ์๊ฐ ๋์ ๋จ์ด์ผ์๋ก
๋ค๋ฅธ ๋ฌธ์์๋ ๋ง์ง ์๊ณ ํด๋น ๋ฌธ์์์ ์์ฃผ ๋ฑ์ฅํ๋ ๋จ์ด
๋ฅผ ์๋ฏธํ๋ค.
์์
Twitter ์์ฐ์ด ์ฒ๋ฆฌ๊ธฐ
-
์์ฐ์ด ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ์ํด ํ์ํ๋ค.
-
Maven
<dependency> <groupId>org.openkoreantext</groupId> <artifactId>open-korean-text</artifactId> <version>2.1.0</version> </dependency>
๋ฌธ์ ์ ๋ณด
- 3๊ฐ์ง์ ์์ ๋ฌธ์๊ฐ ์๋ค๊ณ ๊ฐ์ ํ์.
private static String[] dataList = {
"I love dogs", // I, love, dogs
"I hate dogs and knitting", // I, hate, dogs, and, knitting
"Knitting is my hobby and my passion", // Knitting, is, my, hobby, and, my, passion
};
Tf-IDF ๋ชจ๋ธ ์ ์
class Tf_idf {
private int tf = 0;
private double idf = 0;
public void addTf() {
this.tf = tf + 1;
}
public void setIdf(double idf) {
this.idf = idf;
}
public double getTf_idf() {
return tf * idf;
}
@Override
public String toString() {
return String.format("tf = %d | idf = %.2f | tf-idf = %.2f", tf, idf, getTf_idf());
}
}
Tf๊ฐ ๊ณ์ฐํ๊ธฐ
-
tf๊ฐ์ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์๋ ๋ค์ํ ๋ฐฉ๋ฒ์ด ์๋ค.
- ๋ฌธ์์ ๊ธธ์ด์ ๋ฐ๋ผ ๋จ์ด์ ๋น๋๊ฐ์ ์กฐ์ ํ ์๋ ์๋ค.
- boolean ๋น๋๋ก ํ๋ฒ๋ง ๋ฑ์ฅํด๋ 1๋ก ๊ฐ์ ์ ํ๋ ๊ฒฝ์ฐ๋ ์๋ค.
- log๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ์กฐ์ ํ ์๋ ์๋ค.
-
์๋ ๋ฐฉ๋ฒ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์จ ํ์๋ฅผ countํ๋ค.
// Tf ๊ณ์ฐ
for (String data : dataList) {
// Normalize - ์์ฐ์ด ์ฒ๋ฆฌ
CharSequence normalized = OpenKoreanTextProcessorJava.normalize(data);
// Tokenize - ์์ฐ์ด ์ฒ๋ฆฌ
Seq<KoreanTokenizer.KoreanToken> tokens = OpenKoreanTextProcessorJava.tokenize(normalized);
// documentMap ์์ฑ
HashMap<String, Tf_idf> documentMap = new HashMap<String, Tf_idf>();
// documentMap์ Tf๊ฐ ์
๋ ฅ
for (String token : OpenKoreanTextProcessorJava.tokensToJavaStringList(tokens)) {
if (!documentMap.containsKey(token)) { // document์ token์ด ์์ ๊ฒฝ์ฐ
Tf_idf tokenValue = new Tf_idf();
tokenValue.addTf();
documentMap.put(token, tokenValue);
} else { // document์ token์ด ์๋ ๊ฒฝ์ฐ
Tf_idf tokenValue = documentMap.get(token);
tokenValue.addTf();
}
}
// documentList์ documentMap ์ถ๊ฐ
documentList.add(documentMap);
}
- ๊ฒฐ๊ณผ๊ฐ
Idf๊ฐ ๊ณ์ฐ
log(์ ์ฒด๋ฌธ์์ ์ / token์ด ํฌํจ๋ ๋ฌธ์์ ์)
// idf ๊ณ์ฐ
for (HashMap documentMap : documentList) {
Iterator<String> tokenList = documentMap.keySet().iterator(); // document token ๊ฐ์ ธ์ค๊ธฐ
while (tokenList.hasNext()) {
String token = tokenList.next();
Tf_idf tokenValue = (Tf_idf) documentMap.get(token);
int hit_document = 0;
for (int index = 0; index < documentList.size(); index++) {
if (documentList.get(index).containsKey(token)) { // document์ token์ด ํฌํจํ ๊ฒฝ์ฐ
hit_document++;
}
}
tokenValue.setIdf(Math.log10((double) documentList.size() / hit_document)); // log(์ ์ฒด ๋ฌธ์ / hit ๋ฌธ์)
}
}
- ๊ฒฐ๊ณผ๊ฐ
tf-idf
๊ฐ์ด ๋์์๋ก ๋ค๋ฅธ ๋ฌธ์์ ์ ์ธ๊ธ๋์ง ์์ ๋จ์ด(my, love, hate, hobby, is, passion)์ธ ๊ฒ์ ์ ์ ์๋ค.tf-idf
๊ฐ์ด ๋ฎ์์๋ก ๋ค๋ฅธ ๋ฌธ์์ ์ ์ธ๊ธํ๋ ๋จ์ด(I, dogs, and, knitting)์ธ ๊ฒ์ ์ ์ ์๋ค.
๋ง์น๋ฉฐ
- Tf-IDF์ ๋ชฉ์ ์
๋ค๋ฅธ ๋ฌธ์์ ์์ฃผ ์ธ๊ธ๋์ง ์๊ณ ํด๋น ๋ฌธ์์๋ ์์ฃผ ์ธ๊ธ๋๋ token์ ๋ํด ์ ์๋ฅผ ๋๊ฒ ๋ถ์ฌํ๋ ๊ฒ
. - ์ ํด์ง ๊ณต์์ ์๋ค. ๋ถ์ํ๋
๋ฐ์ดํฐ์ ๋ง๊ฒ
Tf-IDF๋ฅผ ๋ณํํด๊ฐ๋ฉฐ ๋ค์ํ ์๋๋ฅผ ํด๋ณด์.