knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5 )
Welcome to the nmfkc package!
This vignette provides a beginner-friendly introduction to the core function, nmfkc().
Non-negative Matrix Factorization (NMF) is a technique that decomposes a large data matrix $Y$ into two smaller matrices, $X$ and $B$: $$Y \approx X B$$ The key feature of NMF is that all elements must be non-negative ($\ge 0$). This makes the results intuitive, as the original data can be understood as an additive combination of parts.
In this guide, we will cover:
To understand NMF, let's imagine a scenario with 5 Users rating 4 Movies on a scale of 1 to 5.
First, load the package.
library(nmfkc)
We create a rating matrix Y.
The dataset contains two hidden genres: "Action" (Movies 1 & 2) and "Romance" (Movies 3 & 4).
# Rows: Users (U1-U5), Cols: Movies (M1-M4) # U1, U2, U3 prefer Action movies. # U4, U5 prefer Romance movies. Y <- matrix( c(5, 4, 1, 1, 4, 5, 1, 2, 5, 5, 2, 2, 1, 2, 5, 4, 1, 1, 4, 5), nrow = 5, byrow = TRUE ) # Assign names for better interpretation rownames(Y) <- paste0("User", 1:5) colnames(Y) <- c("Action1", "Action2", "Romance1", "Romance2") # Check the data print(Y)
We use the nmfkc() function to decompose this matrix.
Since we assume there are 2 genres (Action and Romance), we set rank = 2.
# Run NMF with rank = 2 res <- nmfkc(Y, rank = 2, seed = 123)
NMF decomposes $Y$ into $X$ (Basis) and $B$ (Coefficient). (Note: The order of bases may vary depending on the random seed. In this example with seed=123, Basis 1 corresponds to Action and Basis 2 to Romance.)
The matrix $X$ represents "How much each User likes each Genre (Basis)."
# Each column represents a latent factor (Basis) res$X
The matrix $B$ represents "Which Genre each Movie belongs to."
# Each row represents a latent factor res$B
As you can see, NMF automatically discovered the hidden structures ("Action" vs "Romance") and user preferences without being explicitly told.
nmfkc provides tools to visually diagnose your model.
Use the plot() function to check if the error minimized properly during iterations.
plot(res, main = "Convergence Plot")
The nmfkc.residual.plot() function allows you to compare the Original Matrix ($Y$), the Fitted Matrix ($XB$), and the Residuals ($E$) side-by-side.
# Visualize Original vs Fitted vs Residuals nmfkc.residual.plot(Y, res)
The middle plot (Fitted Matrix) successfully captures the block structure of the original data.
A powerful feature of nmfkc is its robustness to Missing Values (NA). This is useful for tasks like Recommendation Systems, where you want to predict how a user would rate a movie they haven't seen yet.
Let's assume User1 has not seen Action1 yet. We set this value to NA.
Y_missing <- Y Y_missing["User1", "Action1"] <- NA # Introduce missing value print(Y_missing)
Simply pass the matrix with NAs to nmfkc(). The algorithm automatically handles them by ignoring the missing entries during optimization.
res_na <- nmfkc(Y_missing, rank = 2, seed = 123)
The fitted model ($X \times B$) provides an estimate for the missing entry.
# Extract the predicted value from the fitted matrix XB predicted_rating <- res_na$XB["User1", "Action1"] actual_rating <- Y["User1", "Action1"] # The original hidden value (5) cat(paste0("Actual Rating: ", actual_rating, "\n")) cat(paste0("Predicted Rating: ", round(predicted_rating, 2), "\n"))
Because User1 liked other Action movies, the model predicted a reasonably high rating (3.62) for the missing Action movie, closer to the actual rating (5) than to a low rating.
With the nmfkc package, you can easily:
For more advanced topics, such as Time Series Analysis or Covariate-assisted NMF, please refer to the other vignettes (Topic Modeling and Time Series Analysis).
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.