I've recently finished writing a "simple-as-possible" LDA code in Python.
The theory from which I've developed my code can be found in the book Computer Vision by Simon Prince, free (courtesy of Simon Prince) pdf can be found on his website: http://computervisionmodels.com/ - Chapter 20 talks about LDA. Applied to computer vision, he gives the notation i as the number of images, m as the number of parts or topics, and w as the words.
After re-doing the code today, I've found I get results which I expect (sorting a set of words into two or more topics). I've been comparing to other LDA code which is doing this more accurately and I'm wondering if the way I'm writing the code is making it inefficient. Any feedback appreciated :)
import numpy as np
corpus = open('corpus3.txt').read()
#Creatinig dictionary of unique terms, indexed and counted
dic = {}
arr=[]
arrv=[]
for item in corpus.split():
if item in dic:
dic[item] += 1
else:
dic[item] = 1
arr = dic.keys()
arrv= dic.values()
arrid=range(0,len(arr))
#Replacing actual words in doc with the word id's
Imgvv=[]
for w in corpus.split():
for i in arrid:
if w == arr[i]:
Imgvv.append(i)
Imgv = [Imgvv] # Array of (array of) words in documents (replaced with id's)
Vocab = arr #Vocab of unique terms
I = len(Imgv) #Image number
M = 2 # Part number - hardwired (supervised learning)
V = len(Vocab) #vocabulary
#Dirichlet constants
alpha=0.5
beta=0.5
#Initialise the 4 counters used in Gibbs sampling
Na = np.zeros((I, M)) + alpha # umber of words for each document, topic combo i.e 11, 12,13 -> 21,22,23 array.
Nb = np.zeros(I) + M*alpha # number of words in each image
Nc = np.zeros((M, V)) + beta # word count of each topic and vocabulary, times the word is in topic M and is of vocab number 1,2,3, etc..
Nd = np.zeros(M) + V*beta # number of words in each topic
m_w = [] #topic of the current word
m_i_w=[] # topic of the image of the word
#Filling up counters
for i,img in enumerate(Imgv):
for w in img:
m = np.random.randint(0,M)
m_w.append(m)
Na[i,m] += 1
Nb[i] += 1
Nc[m,w] += 1
Nd[m] += 1
m_i_w.append(np.array(m_w)) #creating a relationship between topic to word per doc
#Gibbs Sampling
m_i=[]
q = np.zeros(M)
for t in xrange(500): #Iterations
for i,img in enumerate(Imgv): #in the Imgv matrix there are i documents which are arrays (img) filled with words
m_w = m_i_w[i] #Finding topic of word
Nab = Na[i] #Taking ith row of the Na counter (array)
for n, w in enumerate(img): #in img there are n words of value w
m = m_w[n] # From the intialised/appended topic-word value we draw the "guessed" topic
Nab[m] -= 1
Nb[i] -= 1 #In Gibbs Samp. we compute for all values except the current (x,y) position
Nc[m,w] -= 1 #So we move the counter of this positon down one, compute
Nd[m] -= 1 #And then add one back after reloading the topic for the word
q = (Nab*(Nc[:,w]))/((Nb[i])*(Nd)) # computing topic probability
q_new = np.random.multinomial(1, q/q.sum()).argmax() # choosing new topic based on this
m_w[n] = q_new # assigning word to topic, replacing the guessed topic from init.
Nab[q_new] += 1 #Putting the counters back to original value before redoing process.
Nb[i] += 1
Nc[q_new,w] += 1
Nd[q_new] += 1
WordDist = Nc/Nd[:, np.newaxis] # This gives us the words per topic
for m in xrange(M): #Displaying results
for w in np.argsort(-WordDist[m])[:20]:
print("Topic", m, Vocab[w], WordDist[m,w],arrv[w])