Estou trabalhando em um projeto no qual desejo extrair algumas informações sobre o conteúdo de uma série de ensaios abertos. Nesse projeto em particular, 148 pessoas escreveram ensaios sobre uma organização hipotética de estudantes como parte de um experimento maior. Embora no meu campo (psicologia social), a maneira típica de analisar esses dados seja codificar os ensaios manualmente, eu gostaria de fazer isso quantitativamente, uma vez que a codificação manual é trabalhosa e um pouco subjetiva demais para o meu trabalho. gosto.
Durante minhas investigações sobre maneiras de analisar quantitativamente os dados de resposta livre, deparei-me com uma abordagem chamada modelagem de tópicos (ou Alocação de Dirichlet Latente, ou LDA). A modelagem de tópicos utiliza uma representação de palavras-chave de seus dados (uma matriz termo-documento) e usa informações sobre as co-ocorrências de palavras para extrair os tópicos latentes dos dados. Essa abordagem parece perfeita para minha aplicação.
Infelizmente, ao aplicar a modelagem de tópicos aos meus dados, descobri dois problemas:
- Os tópicos descobertos pela modelagem de tópicos às vezes são difíceis de interpretar
- Quando eu executo meus modelos de tópicos com uma semente aleatória diferente, os tópicos parecem mudar drasticamente
A edição 2, em particular, me preocupa. Portanto, tenho duas perguntas relacionadas:
- Existe algo que eu possa fazer no procedimento LDA para otimizar meu procedimento de ajuste de modelo para interpretabilidade e estabilidade? Pessoalmente, não me importo muito em encontrar o modelo com a menor perplexidade e / ou melhor ajuste do modelo - quero principalmente usar esse procedimento para me ajudar a entender e caracterizar o que os participantes deste estudo escreveram em seus ensaios. No entanto, certamente não quero que meus resultados sejam um artefato da semente aleatória!
- Relacionado à pergunta acima, existem padrões para a quantidade de dados que você precisa para fazer um LDA? A maioria dos artigos que vi que utilizaram esse método analisam grandes corpora (por exemplo, um arquivo de todos os artigos científicos dos últimos 20 anos), mas, como estou usando dados experimentais, meu corpus de documentos é muito menor.
Publiquei os dados do ensaio aqui para quem quer sujar as mãos e colei o código R que estou usando abaixo.
require(tm)
require(topicmodels)
# Create a corpus from the essay
c <- Corpus(DataframeSource(essays))
inspect(c)
# Remove punctuation and put the words in lower case
c <- tm_map(c, removePunctuation)
c <- tm_map(c, tolower)
# Create a DocumentTermMatrix. The stopwords are the LIWC function word categories
# I have a copy of the LIWC dictionary, but if you want to do a similar analysis,
# use the default stop words in tm
dtm <- DocumentTermMatrix(c, control = list(stopwords =
c(dict$funct, dict$pronoun, dict$ppron, dict$i, dict$we, dict$you, dict$shehe,
dict$they, dict$inpers, dict$article, dict$aux)))
# Term frequency inverse-document frequency to select the desired words
term_tfidf <- tapply(dtm$v/rowSums(as.matrix(dtm))[dtm$i], dtm$j, mean) * log2(nDocs(dtm)/colSums(as.matrix(dtm)))
summary(term_tfidf)
dtm <- dtm[, term_tfidf >= 0.04]
lda <- LDA(dtm, k = 5, seed = 532)
perplexity(lda)
(terms <- terms(lda, 10))
(topics <- topics(lda))
Editar:
Eu tentei modificar nstart
como sugerido por Solha nos comentários. Infelizmente, como mostrado abaixo, até definir nstart
1000 resultados em tópicos que variam bastante de semente aleatória para semente aleatória. Apenas para enfatizar novamente, a única coisa que estou mudando na estimativa dos dois modelos abaixo é a semente aleatória usada para iniciar a estimativa do modelo, e ainda assim os tópicos não parecem consistentes nessas duas execuções.
lda <- LDA(dtm, k = 5, seed = 535, control = list(nstart = 1000))
(terms <- terms(lda, 10))
Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
[1,] "international" "ethnicity" "free" "credit" "kind"
[2,] "communicate" "true" "team" "mandatory" "bridge"
[3,] "gain" "asians" "cooperate" "music" "close"
[4,] "use" "hand" "order" "seen" "deal"
[5,] "big" "hold" "play" "barrier" "designed"
[6,] "communication" "effective" "big" "stereotypes" "effort"
[7,] "america" "emphasis" "beginning" "asians" "implemented"
[8,] "chinese" "halls" "china" "fantastic" "websites"
[9,] "ethnicity" "minorities" "difference" "focusing" "planned"
[10,] "networks" "population" "easier" "force" "body"
lda <- LDA(dtm, k = 5, seed = 536, control = list(nstart = 1000))
(terms <- terms(lda, 10))
Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
[1,] "kind" "international" "issue" "willing" "play"
[2,] "easier" "ethnicity" "close" "use" "trying"
[3,] "gain" "communication" "currently" "hand" "unity"
[4,] "websites" "communicate" "implemented" "networks" "decision"
[5,] "credit" "bridge" "particularly" "stereotypes" "gap"
[6,] "effort" "america" "credit" "communicate" "normally"
[7,] "barriers" "connection" "fulfill" "came" "asians"
[8,] "effects" "kind" "grew" "asians" "created"
[9,] "established" "order" "perspectives" "big" "effective"
[10,] "strangers" "skills" "big" "budget" "prejudice"
nstart
e olhar o site do curso para ver se algum deles produz algo útil. (BTW, se você inserir seus comentários em uma resposta, vou votar. Gostaria de ver se mais alguém tem algum conselho antes de aceitar qualquer coisa, mas acho que seus comentários são mais que suficientes para contar como resposta).
LDA
função notopicmodels
pacote. Em particular, você pode tentarnstart
aumentar. Isso é garantido para tornar seus resultados mais estáveis, porque a função LDA será executada repetidamente com diferentes sementes aleatórias e retornará o melhor resultado. Infelizmente, aumentandonstart
para, digamos, 1000 vai fazer o algoritmo que 1000 vezes mais trabalho (continuação)