Latent semantic analysis methods comparison over random mandalas deconstruction -- WL​
​by Anton Antonov​
​PythonForPrediction at WordPress​
​SimplifiedMachineLearningWorkflows-book at GitHub​
December 2021
February 2022
Mathematica

Introduction

This notebook (and other notebooks) were used in the presentation "Random mandalas deconstruction with R, Python, and Mathematica" given at "Boston useR! Meetup" in February 2022. Here is a link to presentation's recording.
Here is presentation's abstract:
In this presentation we discuss the application of different dimension reduction algorithms over collections of random mandalas. We discuss and compare the derived image bases and show how those bases explain the underlying collection structure. The presented techniques and insights (1) are applicable to any collection of images, and (2) can be included in larger, more complicated machine learning workflows. The former is demonstrated with a handwritten digits recognition
application; the latter with the generation of random Bethlehem stars. The (parallel) walk-through of the core demonstration is in all three programming languages: Mathematica, Python, and R.
Remark: This is a Mathematica notebook with Wolfram Language (WL) code. There are corresponding notebooks with Mathematica/WL and R/RStudio with Python, R, and WL codes.

Workflow

Here is a diagram that shows the overall process followed in all notebooks used in the presentation:
Out[]=

Get Python mandalas collection

Setup

〉
In[]:=
# "Standard" packages
import pandas
import numpy
import random
import io
import time
​
# Plotting packages
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
​
# Image processing package(s)
from PIL import Image, ImageOps
​
# Random mandalas packages
from RandomMandala import random_mandala, figure_to_image
In[]:=
pythonSession=First@Pick[ExternalSessions[],#["System"]=="Python"&/@ExternalSessions[]]
Out[]=
ExternalSessionObject
System: Python
Version: 3.10.2
Name: DefaultPythonSession


Mandala collection

〉
In[]:=
# A list to accumulate random mandala images
mandala_images = []
​
# Generation loop
random.seed(443)
tstart = time.time()
for i in range(512):

# Generate one random mandala figure
fig2 = random_mandala(n_rows=None,
n_columns=None,
radius=[8, 6, 3],
rotational_symmetry_order=6,
symmetric_seed=True,
connecting_function='bezier_fill',
face_color="0.",
alpha = 1.0)
fig2.tight_layout()

# Convert the figure into an image and add it to the list
mandala_images = mandala_images + [figure_to_image(fig2)]

# Close figure to save memoru
plt.close(fig2)
​
# Invert image colors
mandala_images1 = [ImageOps.invert(img) for img in mandala_images]
​
# Binarize images
mandala_images2 = [im.convert('1') for im in mandala_images1]
​
# Resize images
width, height = mandala_images2[0].size
print([width, height])
ratio = height / width
new_width = 200
mandala_images3 = [img.resize((new_width, round(new_width * ratio)), Image.ANTIALIAS) for img in mandala_images2]
print("Process time: " + str(time.time()-tstart))
[640, 480]
Process time: 23.023240089416504

Get mandalas in Mathematica

In[]:=
mandalas3=ExternalEvaluate[pythonSession,"mandala_images3"];​​Length[mandalas3]
Out[]=
512

Process random mandalas collection

Show one of the random mandalas:
In[]:=
mandalas3〚12〛
Out[]=
In[]:=
{imageSizeX,imageSizeY}=ImageDimensions[mandalas3〚12〛]
Out[]=
{200,150}
Show an array of inverted random mandalas:
In[]:=
Multicolumn[RandomSample[mandalas3,36],6]
Out[]=
In[]:=
(*ResourceFunction["RandomMandala"]["SymmetricSeed"->RandomChoice[{True,False}],"RotationalSymmetryOrder"->3,ImageSize->Large,opts]*)
In[]:=
Tally[ImageDimensions/@mandalas3]
Out[]=
{{{200,150},512}}
Convert each image into array and flatten that array:
In[]:=
mandalaArrays=Flatten[ImageData[#]]&/@mandalas3;​​Dimensions[mandalaArrays]
Out[]=
{512,30000}
Make a matrix of flattened mandalas:
In[]:=
mandalaMat=SparseArray[N@mandalaArrays]
Out[]=
SparseArray
Specified elements: 3436475
Dimensions: {512,30000}
Data not saved. Save now

Make the corresponding SSparseMatrix object:
In[]:=
mandalaSMat=ToSSparseMatrix[mandalaMat,"RowNames"->Automatic,"ColumnNames"->Automatic]
Out[]=
SparseArray
Specified elements: 3436475
Dimensions: {512,30000}
Data not saved. Save now


LSAMon object creation

Se the number of topics:
In[]:=
numberOfTopics=40;
Create the LSAMon object:
In[]:=
AbsoluteTiming[​​lsaObj=​​LSAMonUnit[]⟹​​LSAMonSetDocumentTermMatrix[mandalaSMat]⟹​​LSAMonApplyTermWeightFunctions["GlobalWeightFunction"->"None","LocalWeightFunction"->"None","NormalizerFunction"->"None"];​​]
Out[]=
{0.071211,Null}

SVD

Here we extract image topics using Singular Value Decomposition (SVD):
In[]:=
AbsoluteTiming[​​lsaSVDObj=​​lsaObj⟹​​LSAMonExtractTopics["NumberOfTopics"->numberOfTopics,Method->"SVD","MaxSteps"->16,"MinNumberOfDocumentsPerTerm"->0];​​]

NNMF

Here we extract image topics using Non-Negative Matrix Factorization (NNFM):

ICA

Here we extract image topics using Independent Component Analysis (ICA):

Show topics interpretation

SVD

Show the importance coefficients of the topics (if SVD was used the plot would show the singular values):
Show the interpretation of the extracted image topics:

NNMF

Show the importance coefficients of the topics :
Show the interpretation of the extracted image topics:

ICA

Show the importance coefficients of the topics :
Show the interpretation of the extracted image topics:

Approximation

Get a new, unseen random mandala:
Get the generated mandala image in Mathematica:
Get the corresponding vector:

SVD

Represent by topics :

NNMF

ICA