Tengo un dataset que representa 1000 documentos y todas las palabras que aparecen en él. Así que las filas representan los documentos y las columnas representan las palabras. Por ejemplo, el valor en celda $(i,j)$ está parado para los tiempos de palabra $j$ ocurre en el documento $i$. Ahora, tengo que encontrar 'pesos' de las palabras, método de tf/idf, pero realmente no sé cómo hacerlo. ¿Alguien por favor me puede ayudar?
Respuestas
¿Demasiados anuncios?hay paquete tm (minería de textos) http://cran.r-project.org/web/packages/tm/index.html que debe hacer exactamente lo que necesita:
#read 1000 txt articles from directory data/txt
corpus <-Corpus(DirSource("data/txt"), readerControl = list(blank.lines.skip=TRUE));
#some preprocessing
corpus <- tm_map(corpus, removeWords, stopwords("english"))
corpus <- tm_map(corpus, stripWhitespace)
corpus <- tm_map(corpus, stemDocument, language="english")
#creating term matrix with TF-IDF weighting
terms <-DocumentTermMatrix(corpus,control = list(weighting = function(x) weightTfIdf(x, normalize = FALSE)))
#or compute cosine distance among documents
dissimilarity(tdm, method = "cosine")
R es un lenguaje funcional para leer el código puede ser difícil (por ejemplo x en términos)
Wikipedia tiene un buen artículo sobre el tema, completo con fórmulas. Los valores en la matriz son las frecuencias de término. Solo tienes que encontrar las FDI: (log((total documents)/(number of docs with the term))
y múltiples los 2 valores.
En R, podría hacerlo como sigue:
set.seed(42)
d <- data.frame(w=sample(LETTERS, 50, replace=TRUE))
d <- model.matrix(~0+w, data=d)
tf <- d
idf <- log(nrow(d)/colSums(d))
tfidf <- d
for(word in names(idf)){
tfidf[,word] <- tf[,word] * idf[word]
}
Aquí le damos las bases de datos:
> colSums(d)
wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ
3 1 3 1 1 1 1 2 4 2 2 1 1 3 2 2 2 4 5 5 4
> head(d)
wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
3 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
5 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
> head(round(tfidf, 2))
wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ
1 0 0 0 0 0 0.00 0 0 0 0 0.00 0 0 0.00 0 0 0 0.00 2.3 0.0 0
2 0 0 0 0 0 0.00 0 0 0 0 0.00 0 0 0.00 0 0 0 0.00 0.0 2.3 0
3 0 0 0 0 0 3.91 0 0 0 0 0.00 0 0 0.00 0 0 0 0.00 0.0 0.0 0
4 0 0 0 0 0 0.00 0 0 0 0 0.00 0 0 0.00 0 0 0 2.53 0.0 0.0 0
5 0 0 0 0 0 0.00 0 0 0 0 0.00 0 0 2.81 0 0 0 0.00 0.0 0.0 0
6 0 0 0 0 0 0.00 0 0 0 0 3.22 0 0 0.00 0 0 0 0.00 0.0 0.0 0
También puede buscar en el idf de cada término:
> log(nrow(d)/colSums(d))
wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ
2.813411 3.912023 2.813411 3.912023 3.912023 3.912023 3.912023 3.218876 2.525729 3.218876 3.218876 3.912023 3.912023 2.813411 3.218876 3.218876 3.218876 2.525729 2.302585 2.302585 2.525729
El código tiene un error: colSums calcula el número de aparición en el corpus, no el número de textos con la palabra.
Una versión de computación tal sería:
tfidf=function(mat){
tf <- mat
id=function(col){sum(!col==0)}
idf <- log(nrow(mat)/apply(mat, 2, id))
tfidf <- mat
for(word in names(idf)){tfidf[,word] <- tf[,word] * idf[word]}
return(tfidf)
}
Hay un nuevo paquete de R que puede hacer esto: textir: regresión inversa para análisis de texto
El comando correspondiente es tfidf
, el ejemplo del manual:
data(we8there)
## 20 high-variance tf-idf terms
colnames(we8thereCounts)[
order(-sdev(tfidf(we8thereCounts)))[1:20]]