Skip to content

Instantly share code, notes, and snippets.

@sowmyagowri
Created December 12, 2017 00:22
Show Gist options
  • Save sowmyagowri/ac57beee5e2ca57de29fb9d496649311 to your computer and use it in GitHub Desktop.
Save sowmyagowri/ac57beee5e2ca57de29fb9d496649311 to your computer and use it in GitHub Desktop.
Python Program for Text Clustering using Bisecting k-means
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import random\n",
"from collections import defaultdict\n",
"from scipy.sparse import csr_matrix\n",
"from sklearn.utils import shuffle\n",
"from sklearn.metrics import calinski_harabaz_score"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def csr_read(fname, ftype=\"csr\", nidx=1):\n",
" r\"\"\" \n",
" Read CSR matrix from a text file. \n",
" \n",
" \\param fname File name for CSR/CLU matrix\n",
" \\param ftype Input format. Acceptable formats are:\n",
" - csr - Compressed sparse row\n",
" - clu - Cluto format, i.e., CSR + header row with \"nrows ncols nnz\"\n",
" \\param nidx Indexing type in CSR file. What does numbering of feature IDs start with?\n",
" \"\"\"\n",
" \n",
" with open(fname) as f:\n",
" lines = f.readlines()\n",
" \n",
" if ftype == \"clu\":\n",
" p = lines[0].split()\n",
" nrows = int(p[0])\n",
" ncols = int(p[1])\n",
" nnz = long(p[2])\n",
" lines = lines[1:]\n",
" assert(len(lines) == nrows)\n",
" elif ftype == \"csr\":\n",
" nrows = len(lines)\n",
" ncols = 0 \n",
" nnz = 0 \n",
" for i in xrange(nrows):\n",
" p = lines[i].split()\n",
" if len(p) % 2 != 0:\n",
" raise ValueError(\"Invalid CSR matrix. Row %d contains %d numbers.\" % (i, len(p)))\n",
" nnz += len(p)/2\n",
" for j in xrange(0, len(p), 2): \n",
" cid = int(p[j]) - nidx\n",
" if cid+1 > ncols:\n",
" ncols = cid+1\n",
" else:\n",
" raise ValueError(\"Invalid sparse matrix ftype '%s'.\" % ftype)\n",
" val = np.zeros(nnz, dtype=np.float)\n",
" ind = np.zeros(nnz, dtype=np.int)\n",
" ptr = np.zeros(nrows+1, dtype=np.long)\n",
" n = 0 \n",
" for i in xrange(nrows):\n",
" p = lines[i].split()\n",
" for j in xrange(0, len(p), 2): \n",
" ind[n] = int(p[j]) - nidx\n",
" val[n] = float(p[j+1])\n",
" n += 1\n",
" ptr[i+1] = n \n",
" \n",
" assert(n == nnz)\n",
" \n",
" return csr_matrix((val, ind, ptr), shape=(nrows, ncols), dtype=np.float)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def csr_idf(matrix, copy=False, **kargs):\n",
" r\"\"\" Scale a CSR matrix by idf. \n",
" Returns scaling factors as dict. If copy is True, \n",
" returns scaled matrix and scaling factors.\n",
" \"\"\"\n",
" if copy is True:\n",
" matrix = matrix.copy()\n",
" nrows = matrix.shape[0]\n",
" nnz = matrix.nnz\n",
" ind, val, ptr = matrix.indices, matrix.data, matrix.indptr\n",
" # document frequency\n",
" df = defaultdict(int)\n",
" for i in ind:\n",
" df[i] += 1\n",
" # inverse document frequency\n",
" for k,v in df.items():\n",
" df[k] = np.log(nrows / float(v)) ## df turns to idf - reusing memory\n",
" # scale by idf\n",
" for i in range(0, nnz):\n",
" val[i] *= df[ind[i]]\n",
" \n",
" return df if copy is False else matrix"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def csr_l2normalize(matrix, copy=False, **kargs):\n",
" r\"\"\" Normalize the rows of a CSR matrix by their L-2 norm. \n",
" If copy is True, returns a copy of the normalized matrix.\n",
" \"\"\"\n",
" if copy is True:\n",
" matrix = matrix.copy()\n",
" nrows = matrix.shape[0]\n",
" nnz = matrix.nnz\n",
" ind, val, ptr = matrix.indices, matrix.data, matrix.indptr\n",
" # normalize\n",
" for i in range(nrows):\n",
" rsum = 0.0 \n",
" for j in range(ptr[i], ptr[i+1]):\n",
" rsum += val[j]**2\n",
" if rsum == 0.0:\n",
" continue # do not normalize empty rows\n",
" rsum = float(1.0/np.sqrt(rsum))\n",
" for j in range(ptr[i], ptr[i+1]):\n",
" val[j] *= rsum\n",
" \n",
" if copy is True:\n",
" return matrix"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def initialCentroids(matrix):\n",
" matrixShuffled = shuffle(matrix, random_state=0)\n",
" return matrixShuffled[:2,:]"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def similarity(matrix, centroids):\n",
" similarities = matrix.dot(centroids.T)\n",
" return similarities"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def findClusters(matrix, centroids):\n",
" \n",
" clusterA = list()\n",
" clusterB = list()\n",
" \n",
" similarityMatrix = similarity(matrix, centroids)\n",
" \n",
" for index in range(similarityMatrix.shape[0]):\n",
" similarityRow = similarityMatrix[index]\n",
" \n",
" #Sort the index of the matrix in ascending order of value and get the index of the last element\n",
" #This index will be the cluster that the row in input matrix will belong to\n",
" similaritySorted = np.argsort(similarityRow)[-1]\n",
" \n",
" if similaritySorted == 0:\n",
" clusterA.append(index)\n",
" else:\n",
" clusterB.append(index)\n",
" \n",
" return clusterA, clusterB"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def recalculateCentroid(matrix, clusters):\n",
" centroids = list()\n",
" \n",
" for i in range(0,2):\n",
" cluster = matrix[clusters[i],:]\n",
" clusterMean = cluster.mean(0)\n",
" centroids.append(clusterMean)\n",
" \n",
" centroids_array = np.asarray(centroids)\n",
" \n",
" return centroids_array"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def kmeans(matrix, numberOfIterations):\n",
" \n",
" centroids = initialCentroids(matrix)\n",
" \n",
" for _ in range(numberOfIterations):\n",
" \n",
" clusters = list()\n",
" \n",
" clusterA, clusterB = findClusters(matrix, centroids)\n",
" \n",
" if len(clusterA) > 1:\n",
" clusters.append(clusterA)\n",
" if len(clusterB) > 1:\n",
" clusters.append(clusterB)\n",
" \n",
" centroids = recalculateCentroid(matrix, clusters)\n",
" \n",
" return clusterA, clusterB"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def calculateSSE(matrix, clusters):\n",
" \n",
" SSE_list = list()\n",
" SSE_array = []\n",
" \n",
" for cluster in clusters:\n",
" members = matrix[cluster,:]\n",
" SSE = np.sum(np.square(members - np.mean(members)))\n",
" SSE_list.append(SSE)\n",
" \n",
" SSE_array = np.asarray(SSE_list)\n",
" dropClusterIndex = np.argsort(SSE_array)[-1]\n",
" \n",
" return dropClusterIndex"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def bisecting_kmeans(matrix, k, numberOfIterations):\n",
" \n",
" clusters = list()\n",
" \n",
" initialcluster = list()\n",
" for i in range(matrix.shape[0]):\n",
" initialcluster.append(i)\n",
" \n",
" clusters.append(initialcluster)\n",
" \n",
" while len(clusters) < k:\n",
"\n",
" dropClusterIndex = calculateSSE(matrix, clusters)\n",
" droppedCluster = clusters[dropClusterIndex]\n",
" \n",
" clusterA, clusterB = kmeans(matrix[droppedCluster,:], numberOfIterations)\n",
" del clusters[dropClusterIndex]\n",
" \n",
" actualClusterA = list()\n",
" actualClusterB = list()\n",
" for index in clusterA:\n",
" actualClusterA.append(droppedCluster[index])\n",
" \n",
" for index in clusterB:\n",
" actualClusterB.append(droppedCluster[index])\n",
" \n",
" clusters.append(actualClusterA)\n",
" clusters.append(actualClusterB)\n",
" \n",
" labels = [0] * matrix.shape[0]\n",
"\n",
" for index, cluster in enumerate(clusters):\n",
" for idx in cluster:\n",
" labels[idx] = index + 1\n",
" return labels"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#Read CSR matrix from the input file\n",
"csrMatrix = csr_read('train.dat', ftype=\"csr\", nidx=1)\n",
"\n",
"#Scale the CSR matrix by idf (Inverse Document Frequency)\n",
"csrIDF = csr_idf(csrMatrix, copy=True)\n",
"\n",
"#Normalize the rows of a CSR matrix by their L-2 norm.\n",
"csrL2Normalized = csr_l2normalize(csrIDF, copy=True)\n",
"\n",
"#Obtain a dense ndarray representation of the CSR matrix.\n",
"denseMatrix = csrL2Normalized.toarray()"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"For K= 3 Calinski Harabaz Score is 63.080976\n",
"For K= 5 Calinski Harabaz Score is 47.311063\n",
"For K= 7 Calinski Harabaz Score is 46.035433\n",
"For K= 9 Calinski Harabaz Score is 43.216868\n",
"For K= 11 Calinski Harabaz Score is 38.217769\n",
"For K= 13 Calinski Harabaz Score is 34.761864\n",
"For K= 15 Calinski Harabaz Score is 34.206359\n",
"For K= 17 Calinski Harabaz Score is 32.649491\n",
"For K= 19 Calinski Harabaz Score is 30.837459\n",
"For K= 21 Calinski Harabaz Score is 30.097737\n"
]
}
],
"source": [
"kValues = list()\n",
"scores = list()\n",
"\n",
"for k in range(3, 22, 2):\n",
" labels = bisecting_kmeans(denseMatrix, k, 10)\n",
" \n",
" if (k == 7):\n",
" # write result to output file\n",
" outputFile = open(\"output.dat\", \"w\")\n",
" for index in labels:\n",
" outputFile.write(str(index) +'\\n')\n",
" outputFile.close()\n",
"\n",
" score = calinski_harabaz_score(denseMatrix, labels)\n",
" kValues.append(k)\n",
" scores.append(score)\n",
" \n",
" print (\"For K= %d Calinski Harabaz Score is %f\" %(k, score))"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0xea46e80>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"\n",
"plt.plot(kValues, scores)\n",
"plt.xticks(kValues, kValues)\n",
"plt.xlabel('Number of Clusters k')\n",
"plt.ylabel('Calinski and Harabaz Score')\n",
"plt.title('Trend of Average Distance to Centroid/Diameter')\n",
"plt.grid(linestyle='dotted')\n",
"\n",
"plt.savefig('plot.png')\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment