This example shows how to use the riemannianStats
package to explore a small student data set and reduce its
dimensionality using Riemannian principal component analysis.
The data set contains the grades of 10 students in 5 subjects: Mathematics, Sciences, Spanish, History, and Physical Education.
The objective is not to classify students or use predefined groups, but to explore the general structure of the data using Riemannian principal components based on UMAP similarities.
The data set contains one row per student. The first column identifies the student, while the remaining columns contain grades in five subjects.
students <- data.frame(
Student = c(
"Lucia", "Pedro", "Ines", "Luis", "Andres",
"Ana", "Carlos", "Jose", "Sonia", "Maria"
),
Mathematics = c(7, 7.5, 7.6, 5, 6, 7.8, 6.3, 7.9, 6, 6.8),
Sciences = c(6.5, 9.4, 9.2, 6.5, 6, 9.6, 6.4, 9.7, 6, 7.2),
Spanish = c(9.2, 7.3, 8, 6.5, 7.8, 7.7, 8.2, 7.5, 6.5, 8.7),
History = c(8.6, 7, 8, 7, 8.9, 8, 9, 8, 5.5, 9),
PhysicalEducation = c(8, 7, 7.5, 9, 7.3, 6.5, 7.2, 6, 8.7, 7)
)
students
#> Student Mathematics Sciences Spanish History PhysicalEducation
#> 1 Lucia 7.0 6.5 9.2 8.6 8.0
#> 2 Pedro 7.5 9.4 7.3 7.0 7.0
#> 3 Ines 7.6 9.2 8.0 8.0 7.5
#> 4 Luis 5.0 6.5 6.5 7.0 9.0
#> 5 Andres 6.0 6.0 7.8 8.9 7.3
#> 6 Ana 7.8 9.6 7.7 8.0 6.5
#> 7 Carlos 6.3 6.4 8.2 9.0 7.2
#> 8 Jose 7.9 9.7 7.5 8.0 6.0
#> 9 Sonia 6.0 6.0 6.5 5.5 8.7
#> 10 Maria 6.8 7.2 8.7 9.0 7.0The Riemannian PCA is applied only to numeric variables. Therefore, the student names are used as row names, while only the subject grades are kept in the data matrix used for the analysis.
data.analysis <- students[, c(
"Mathematics",
"Sciences",
"Spanish",
"History",
"PhysicalEducation"
)]
student.names <- students$Student
rownames(data.analysis) <- student.names
data.analysis
#> Mathematics Sciences Spanish History PhysicalEducation
#> Lucia 7.0 6.5 9.2 8.6 8.0
#> Pedro 7.5 9.4 7.3 7.0 7.0
#> Ines 7.6 9.2 8.0 8.0 7.5
#> Luis 5.0 6.5 6.5 7.0 9.0
#> Andres 6.0 6.0 7.8 8.9 7.3
#> Ana 7.8 9.6 7.7 8.0 6.5
#> Carlos 6.3 6.4 8.2 9.0 7.2
#> Jose 7.9 9.7 7.5 8.0 6.0
#> Sonia 6.0 6.0 6.5 5.5 8.7
#> Maria 6.8 7.2 8.7 9.0 7.0The riem.pca() function performs the complete Riemannian
PCA workflow internally. The Riemannian structure is constructed from a
similarity matrix, which can be calculated using three methods:
"umap" constructs similarities from a
neighborhood-based structure."isomap" uses a neighborhood graph and geodesic
distances to represent the manifold structure."dbscan" constructs similarities using the
density-based structure identified by DBSCAN.In this example, the similarity matrix is calculated using UMAP. To
use ISOMAP or DBSCAN, only the value of the method argument
needs to be changed to "isomap" or "dbscan",
respectively.
The argument scale.unit = FALSE indicates that the
original variables are used without standardization. The model
calculates five principal components through ncp = 5, while
the first two axes are selected for visualization using
axes = c(1, 2).
modelo <- riem.pca(
data = data.analysis,
scale.unit = FALSE,
ncp = 5,
axes = c(1, 2),
n.neighbors = 3,
min.dist = 0.1,
metric = "euclidean",
method = "umap"
)
modelo
#> Riemannian Principal Component Analysis
#> Similarity method: umap
#> Number of observations: 10
#> Number of variables: 5
#> Number of retained dimensions: 2
#>
#> Eigenvalues:
#> eigenvalue percentage of variance cumulative percentage of variance
#> comp 1 2.7839 55.6775 55.6775
#> comp 2 2.0214 40.4275 96.1050
#> comp 3 0.1020 2.0391 98.1441
#> comp 4 0.0882 1.7632 99.9073
#> comp 5 0.0046 0.0927 100.0000For example, the other similarity methods can be selected as follows:
Some arguments are method-specific. In particular,
min.dist is used by UMAP and does not affect the ISOMAP or
DBSCAN calculations.
The eigenvalues summarize the amount of inertia explained by each Riemannian principal component. The second and third columns show the percentage of explained inertia and the cumulative percentage, respectively.
round(modelo$eig, 4)
#> eigenvalue percentage of variance cumulative percentage of variance
#> comp 1 2.7839 55.6775 55.6775
#> comp 2 2.0214 40.4275 96.1050
#> comp 3 0.1020 2.0391 98.1441
#> comp 4 0.0882 1.7632 99.9073
#> comp 5 0.0046 0.0927 100.0000The inertia explained by the first two components is useful for interpreting the principal plane.
The similarity matrix describes the local relationships between students. Larger values indicate greater similarity between two students according to their grade profiles.
umap.similarities <- modelo$ind$similarities
round(umap.similarities, 3)
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 0.000 0.000 0.000 0.000 0 0.585 0.000 0.000 1.000
#> Pedro 0.000 0.000 0.828 0.000 0.000 1 0.000 0.585 0.000 0.000
#> Ines 0.000 0.828 0.000 0.000 0.000 1 0.000 0.000 0.000 0.000
#> Luis 0.000 0.000 0.000 0.000 0.585 0 0.000 0.000 1.000 0.000
#> Andres 0.000 0.000 0.000 0.585 0.000 0 1.000 0.000 0.585 0.585
#> Ana 0.000 1.000 1.000 0.000 0.000 0 0.000 1.000 0.000 0.000
#> Carlos 0.585 0.000 0.000 0.000 1.000 0 0.000 0.000 0.000 1.000
#> Jose 0.000 0.585 0.000 0.000 0.000 1 0.000 0.000 0.000 0.000
#> Sonia 0.000 0.000 0.000 1.000 0.585 0 0.000 0.000 0.000 0.000
#> Maria 1.000 0.000 0.000 0.000 0.585 0 1.000 0.000 0.000 0.000
#> attr(,"n.neighbors")
#> [1] 3
#> attr(,"min.dist")
#> [1] 0.1
#> attr(,"metric")
#> [1] "euclidean"
#> attr(,"type")
#> [1] "umap_fuzzy_graph_similarity"The Rho matrix is the Riemannian dissimilarity matrix derived from the similarity matrix. It is used to weight the differences between observations.
rho <- modelo$ind$rho
round(rho, 3)
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 1.000 1.000 1.000 1.000 1.000 1 0.415 1.000 1.000 0.000
#> Pedro 1.000 1.000 0.172 1.000 1.000 0 1.000 0.415 1.000 1.000
#> Ines 1.000 0.172 1.000 1.000 1.000 0 1.000 1.000 1.000 1.000
#> Luis 1.000 1.000 1.000 1.000 0.415 1 1.000 1.000 0.000 1.000
#> Andres 1.000 1.000 1.000 0.415 1.000 1 0.000 1.000 0.415 0.415
#> Ana 1.000 0.000 0.000 1.000 1.000 1 1.000 0.000 1.000 1.000
#> Carlos 0.415 1.000 1.000 1.000 0.000 1 1.000 1.000 1.000 0.000
#> Jose 1.000 0.415 1.000 1.000 1.000 0 1.000 1.000 1.000 1.000
#> Sonia 1.000 1.000 1.000 0.000 0.415 1 1.000 1.000 1.000 1.000
#> Maria 0.000 1.000 1.000 1.000 0.415 1 0.000 1.000 1.000 1.000
#> attr(,"n.neighbors")
#> [1] 3
#> attr(,"min.dist")
#> [1] 0.1
#> attr(,"metric")
#> [1] "euclidean"
#> attr(,"type")
#> [1] "umap_fuzzy_graph_similarity"The Riemannian differences compare each student with the others while taking the local similarity structure into account.
riemannian.diff <- modelo$ind$differences
round(riemannian.diff, 3)
#> , , Mathematics
#>
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 -0.500 -0.600 2.000 1.000 -0.8 0.291 -0.900 1.0 0.000
#> Pedro 0.500 0.000 -0.017 2.500 1.500 0.0 1.200 -0.166 1.5 0.700
#> Ines 0.600 0.017 0.000 2.600 1.600 0.0 1.300 -0.300 1.6 0.800
#> Luis -2.000 -2.500 -2.600 0.000 -0.415 -2.8 -1.300 -2.900 0.0 -1.800
#> Andres -1.000 -1.500 -1.600 0.415 0.000 -1.8 0.000 -1.900 0.0 -0.332
#> Ana 0.800 0.000 0.000 2.800 1.800 0.0 1.500 0.000 1.8 1.000
#> Carlos -0.291 -1.200 -1.300 1.300 0.000 -1.5 0.000 -1.600 0.3 0.000
#> Jose 0.900 0.166 0.300 2.900 1.900 0.0 1.600 0.000 1.9 1.100
#> Sonia -1.000 -1.500 -1.600 0.000 0.000 -1.8 -0.300 -1.900 0.0 -0.800
#> Maria 0.000 -0.700 -0.800 1.800 0.332 -1.0 0.000 -1.100 0.8 0.000
#>
#> , , Sciences
#>
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 -2.900 -2.700 0.000 0.500 -3.1 0.042 -3.200 0.5 0.000
#> Pedro 2.900 0.000 0.034 2.900 3.400 0.0 3.000 -0.125 3.4 2.200
#> Ines 2.700 -0.034 0.000 2.700 3.200 0.0 2.800 -0.500 3.2 2.000
#> Luis 0.000 -2.900 -2.700 0.000 0.208 -3.1 0.100 -3.200 0.0 -0.700
#> Andres -0.500 -3.400 -3.200 -0.208 0.000 -3.6 0.000 -3.700 0.0 -0.498
#> Ana 3.100 0.000 0.000 3.100 3.600 0.0 3.200 0.000 3.6 2.400
#> Carlos -0.042 -3.000 -2.800 -0.100 0.000 -3.2 0.000 -3.300 0.4 0.000
#> Jose 3.200 0.125 0.500 3.200 3.700 0.0 3.300 0.000 3.7 2.500
#> Sonia -0.500 -3.400 -3.200 0.000 0.000 -3.6 -0.400 -3.700 0.0 -1.200
#> Maria 0.000 -2.200 -2.000 0.700 0.498 -2.4 0.000 -2.500 1.2 0.000
#>
#> , , Spanish
#>
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 1.900 1.200 2.70 1.400 1.5 0.415 1.700 2.70 0.000
#> Pedro -1.900 0.000 -0.121 0.80 -0.500 0.0 -0.900 -0.083 0.80 -1.400
#> Ines -1.200 0.121 0.000 1.50 0.200 0.0 -0.200 0.500 1.50 -0.700
#> Luis -2.700 -0.800 -1.500 0.00 -0.540 -1.2 -1.700 -1.000 0.00 -2.200
#> Andres -1.400 0.500 -0.200 0.54 0.000 0.1 0.000 0.300 0.54 -0.374
#> Ana -1.500 0.000 0.000 1.20 -0.100 0.0 -0.500 0.000 1.20 -1.000
#> Carlos -0.415 0.900 0.200 1.70 0.000 0.5 0.000 0.700 1.70 0.000
#> Jose -1.700 0.083 -0.500 1.00 -0.300 0.0 -0.700 0.000 1.00 -1.200
#> Sonia -2.700 -0.800 -1.500 0.00 -0.540 -1.2 -1.700 -1.000 0.00 -2.200
#> Maria 0.000 1.400 0.700 2.20 0.374 1.0 0.000 1.200 2.20 0.000
#>
#> , , History
#>
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 1.600 0.600 1.600 -0.300 0.6 -0.166 0.600 3.100 0.000
#> Pedro -1.600 0.000 -0.172 0.000 -1.900 0.0 -2.000 -0.415 1.500 -2.000
#> Ines -0.600 0.172 0.000 1.000 -0.900 0.0 -1.000 0.000 2.500 -1.000
#> Luis -1.600 0.000 -1.000 0.000 -0.789 -1.0 -2.000 -1.000 0.000 -2.000
#> Andres 0.300 1.900 0.900 0.789 0.000 0.9 0.000 0.900 1.411 -0.042
#> Ana -0.600 0.000 0.000 1.000 -0.900 0.0 -1.000 0.000 2.500 -1.000
#> Carlos 0.166 2.000 1.000 2.000 0.000 1.0 0.000 1.000 3.500 0.000
#> Jose -0.600 0.415 0.000 1.000 -0.900 0.0 -1.000 0.000 2.500 -1.000
#> Sonia -3.100 -1.500 -2.500 0.000 -1.411 -2.5 -3.500 -2.500 0.000 -3.500
#> Maria 0.000 2.000 1.000 2.000 0.042 1.0 0.000 1.000 3.500 0.000
#>
#> , , PhysicalEducation
#>
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 1.000 0.500 -1.000 0.700 1.5 0.332 2.000 -0.700 0.000
#> Pedro -1.000 0.000 -0.086 -2.000 -0.300 0.0 -0.200 0.415 -1.700 0.000
#> Ines -0.500 0.086 0.000 -1.500 0.200 0.0 0.300 1.500 -1.200 0.500
#> Luis 1.000 2.000 1.500 0.000 0.706 2.5 1.800 3.000 0.000 2.000
#> Andres -0.700 0.300 -0.200 -0.706 0.000 0.8 0.000 1.300 -0.581 0.125
#> Ana -1.500 0.000 0.000 -2.500 -0.800 0.0 -0.700 0.000 -2.200 -0.500
#> Carlos -0.332 0.200 -0.300 -1.800 0.000 0.7 0.000 1.200 -1.500 0.000
#> Jose -2.000 -0.415 -1.500 -3.000 -1.300 0.0 -1.200 0.000 -2.700 -1.000
#> Sonia 0.700 1.700 1.200 0.000 0.581 2.2 1.500 2.700 0.000 1.700
#> Maria 0.000 0.000 -0.500 -2.000 -0.125 0.5 0.000 1.000 -1.700 0.000The Riemannian distance matrix is computed from the Riemannian differences. It summarizes the pairwise distances between students under the Riemannian structure.
distance.matrix <- modelo$ind$distance.matrix
round(distance.matrix, 3)
#> Lucia Pedro Ines Luis Andres Ana Carlos Jose Sonia Maria
#> Lucia 0.000 3.979 3.114 3.854 1.947 3.887 0.629 4.278 4.317 0.000
#> Pedro 3.979 0.000 0.230 4.393 4.214 0.000 3.910 0.628 4.426 3.360
#> Ines 3.114 0.230 0.000 4.422 3.700 0.000 3.265 1.685 4.769 2.526
#> Luis 3.854 4.393 4.422 0.000 1.275 5.113 3.439 5.445 0.000 4.071
#> Andres 1.947 4.214 3.700 1.275 0.000 4.202 0.000 4.460 1.619 0.718
#> Ana 3.887 0.000 0.000 5.113 4.202 0.000 3.772 0.000 5.360 3.002
#> Carlos 0.629 3.910 3.265 3.439 0.000 3.772 0.000 4.047 4.200 0.000
#> Jose 4.278 0.628 1.685 5.445 4.460 0.000 4.047 0.000 5.643 3.302
#> Sonia 4.317 4.426 4.769 0.000 1.619 5.360 4.200 5.643 0.000 4.697
#> Maria 0.000 3.360 2.526 4.071 0.718 3.002 0.000 3.302 4.697 0.000The Riemannian covariance matrix summarizes the joint variability between subjects after incorporating the Riemannian structure of the observations.
covariance.matrix <- modelo$var$cov
round(covariance.matrix, 3)
#> Mathematics Sciences Spanish History PhysicalEducation
#> Mathematics 0.733 1.068 0.198 0.211 -0.620
#> Sciences 1.068 2.303 -0.551 -0.568 -0.620
#> Spanish 0.198 -0.551 1.471 1.782 -0.684
#> History 0.211 -0.568 1.782 2.325 -0.896
#> PhysicalEducation -0.620 -0.620 -0.684 -0.896 0.841The Riemannian correlation matrix expresses the relationships between variables on a common scale.
correlation.matrix <- modelo$var$cor
round(correlation.matrix, 3)
#> Mathematics Sciences Spanish History PhysicalEducation
#> Mathematics 1.000 0.822 0.191 0.162 -0.790
#> Sciences 0.822 1.000 -0.300 -0.245 -0.446
#> Spanish 0.191 -0.300 1.000 0.963 -0.615
#> History 0.162 -0.245 0.963 1.000 -0.641
#> PhysicalEducation -0.790 -0.446 -0.615 -0.641 1.000The individual coordinates represent the students in the reduced Riemannian principal component space.
individual.coordinates <- modelo$ind$coord
round(individual.coordinates, 3)
#> Dim.1 Dim.2
#> Lucia 0.000 0.000
#> Pedro -0.494 -2.358
#> Ines -0.208 -1.741
#> Luis -3.729 0.168
#> Andres -0.471 0.260
#> Ana 0.460 -2.246
#> Carlos 0.000 0.000
#> Jose 0.762 -2.474
#> Sonia -3.554 -0.603
#> Maria 0.000 0.000The variable coordinates are used to interpret the relationship between the original subjects and the Riemannian principal components.
The easiest way to plot the individuals is to pass the full
riem.pca object to riem.plot() and set
choix = "ind".
The correlation circle is obtained by passing the full
riem.pca object to riem.plot() and setting
choix = "var".
The biplot combines the individual principal plane with the variable arrows in a single visualization.
The package also allows plotting by manually passing the data, coordinates and explained inertia. This option is useful when the user has computed the components separately.
riem.plot(
data = modelo$data,
choix = "ind",
components = modelo$ind$coord,
explained.inertia = inertia,
title = "Riemannian PCA"
)The same manual approach can be used for the correlation circle by passing the variable coordinates directly.
riem.plot(
data = modelo$data,
choix = "var",
correlations = modelo$var$coord,
explained.inertia = inertia,
title = "Riemannian PCA"
)This example shows how to use riem.pca() as a complete
workflow for Riemannian principal component analysis. The function
stores the most important objects inside a single result, including
similarities, the Rho matrix, Riemannian differences, distances,
covariance and correlation matrices, individual coordinates, variable
coordinates, and explained inertia.
The object can then be explored directly with components such as
modelo$eig, modelo$ind$coord, and
modelo$var$coord, or visualized with
riem.plot() and riem.biplot().