Reproducir gráfico de proyección de análisis discriminante lineal

9

Estoy luchando con los puntos de proyección en el análisis discriminante lineal (LDA). Muchos libros sobre métodos estadísticos multivariados ilustran la idea de la LDA con la siguiente figura.

Figura 1

La descripción del problema es la siguiente. Primero necesitamos dibujar el límite de decisión, agregar una línea perpendicular y luego trazar proyecciones de puntos de datos en ella. Me pregunto cómo agregar puntos de proyección a la línea perpendicular.

¿Alguna sugerencia / punteros?

Andrej
fuente
2
Aunque en el caso de 2 clases es factible tomar la decisión boudary primero y el eje discriminante segundo, la lógica real de LDA es opuesta. Primero tiene que dibujar las líneas discriminantes. Vea una pregunta (+ enlaces importantes en los comentarios allí) cómo dibujar discriminantes. Y sobre los límites: 1 , 2 .
ttnphns
1
Andrej Extraer los vectores propios. Sabemos que los valores de los discriminantes (puntajes discriminantes) dependen de ellos. El punto clave ahora es que, dado que desea mostrar puntajes discriminantes en el espacio de las variables originales (centradas), debe conceptualizar los discriminantes a medida que las variables originales rotan en ese espacio (exactamente como conceptualizamos los componentes principales). La rotación es la multiplicación de los datos centrados originales por una matriz de rotación ...
ttnphns
1
(Cont.) La matriz cuyas columnas son los vectores propios se puede ver como una matriz de rotación si la suma de los cuadrados de cada una de sus columnas (es decir, cada vector propio) está normalizada por unidad. Entonces, normalice los vectores propios y calcule los puntajes de los componentes como datos centrados multiplicados por estos vectores propios.
ttnphns
1
(Cont.) Lo que queda es mostrar los ejes de los discriminantes como líneas rectas en mosaico por puntos que representan los puntajes discriminantes. Entonces, para trazar la línea de mosaico, tenemos que encontrar las coordenadas de cada punto de mosaico en los ejes originales (las variables). Las coordenadas son fáciles de calcular: cada coordenada es el cathetus, la puntuación discriminante es la hipotenuze, y el cos del ángulo entre ellos es el elemento correspondiente de la matriz del vector propio: cathet = hypoth * cos.
ttnphns
1
Andrej, por lo que el eje discriminante (la sobre la cual se proyectan los puntos en su figura 1) viene dado por la primera vector propio de . En el caso de solo dos clases, este vector propio es igual a , donde son centroides de clase. Normalice este vector (o el vector propio obtenido) para obtener el vector de eje unitario . Esto es suficiente para dibujar el eje. Para proyectar los puntos (centrados) en este eje, simplemente calcule . Aquí es un proyector lineal sobre . Parece que ya casi estás allí, así que tal vez puedas editar tu publicación para explicar exactamente dónde estás atascado. W-1siW-1(metro1-metro2)metroyovXvvvvv
ameba

Respuestas:

6

El primer eje propio de eje discriminante (sobre el cual se proyectan los puntos en la Figura 1) . En el caso de solo dos clases, este vector propio es proporcional a , donde son centroides de clase. Normalice este vector (o el vector propio obtenido) para obtener el vector de eje unitario . Esto es suficiente para dibujar el eje.W-1siW-1(metro1-metro2)metroyov

Para proyectar los puntos (centrados) en este eje, simplemente calcule . Aquí es un proyector lineal sobre .Xvvvvv

Aquí está la muestra de datos de su Dropbox y la proyección LDA:

Proyección LDA

Aquí está el código MATLAB para producir esta figura (según lo solicitado):

% # data taken from your example
X = [-0.9437    -0.0433; -2.4165    -0.5211; -2.0249    -1.0120; ...
    -3.7482 0.2826; -3.3314 0.1653; -3.1927 0.0043; -2.2233 -0.8607; ...
    -3.1965 0.7736; -2.5039 0.2960; -4.4509 -0.3555];
G = [1 1 1 1 1 2 2 2 2 2];

% # overall mean
mu = mean(X);

% # loop over groups
for g=1:max(G)
    mus(g,:) = mean(X(G==g,:)); % # class means
    Ng(g) = length(find(G==g)); % # number of points per group
end

Sw = zeros(size(X,2)); % # within-class scatter matrix
Sb = zeros(size(X,2)); % # between-class scatter matrix
for g=1:max(G)
    Xg = bsxfun(@minus, X(G==g,:), mus(g,:)); % # centred group data
    Sw = Sw + transpose(Xg)*Xg;
    Sb = Sb + Ng(g)*(transpose(mus(g,:) - mu)*(mus(g,:) - mu));
end

St = transpose(bsxfun(@minus,X,mu)) * bsxfun(@minus,X,mu); % # total scatter matrix
assert(sum(sum((St-Sw-Sb).^2)) < 1e-10, 'Error: Sw + Sb ~= St')

% # LDA
[U,S] = eig(Sw\Sb);

% # projecting data points onto the first discriminant axis
Xcentred = bsxfun(@minus, X, mu);
Xprojected = Xcentred * U(:,1)*transpose(U(:,1));
Xprojected = bsxfun(@plus, Xprojected, mu);

% # preparing the figure
colors = [1 0 0; 0 0 1];
figure
hold on
axis([-5 0 -2.5 2.5])
axis square

% # plot discriminant axis
plot(mu(1) + U(1,1)*[-2 2], mu(2) + U(2,1)*[-2 2], 'k')
% # plot projection lines for each data point
for i=1:size(X,1)
    plot([X(i,1) Xprojected(i,1)], [X(i,2) Xprojected(i,2)], 'k--')
end
% # plot projected points
scatter(Xprojected(:,1), Xprojected(:,2), [], colors(G, :))
% # plot original points
scatter(X(:,1), X(:,2), [], colors(G, :), 'filled')
ameba
fuente
Excelente! Tan útil, una pregunta: ¿por qué estamos interesados ​​en el primer vector propio solo?
con gafas
5

Y "mi" solución. ¡Muchas gracias a @ttnphns y @amoeba!

set.seed(2014)
library(MASS)
library(DiscriMiner) # For scatter matrices
library(ggplot2)
library(grid)
# Generate multivariate data
mu1 <- c(2, -3)
mu2 <- c(2, 5)
rho <- 0.6
s1 <- 1
s2 <- 3
Sigma <- matrix(c(s1^2, rho * s1 * s2, rho * s1 * s2, s2^2), byrow = TRUE, nrow = 2)
n <- 50
# Multivariate normal sampling
X1 <- mvrnorm(n, mu = mu1, Sigma = Sigma)
X2 <- mvrnorm(n, mu = mu2, Sigma = Sigma)
X <- rbind(X1, X2)
# Center data
Z <- scale(X, scale = FALSE)
# Class variable
y <- rep(c(0, 1), each = n)

# Scatter matrices
B <- betweenCov(variables = X, group = y)
W <- withinCov(variables = X, group = y)

# Eigenvectors
ev <- eigen(solve(W) %*% B)$vectors
slope <- - ev[1,1] / ev[2,1]
intercept <- ev[2,1]

# Create projections on 1st discriminant
P <- Z %*% ev[,1] %*% t(ev[,1])

# ggplo2 requires data frame
my.df <- data.frame(Z1 = Z[, 1], Z2 = Z[, 2], P1 = P[, 1], P2 = P[, 2])

plt <- ggplot(data = my.df, aes(Z1, Z2))
plt <- plt + geom_segment(aes(xend = P1, yend = P2), size = 0.2, color = "gray")
plt <- plt + geom_point(aes(color = factor(y)))
plt <- plt + geom_point(aes(x = P1, y = P2, colour = factor(y)))
plt <- plt + scale_colour_brewer(palette = "Set1")
plt <- plt + geom_abline(intercept = intercept, slope = slope, size = 0.2)
plt <- plt + coord_fixed()
plt <- plt + xlab(expression(X[1])) + ylab(expression(X[2]))
plt <- plt + theme_bw()
plt <- plt + theme(axis.title.x = element_text(size = 8),
                   axis.text.x  = element_text(size = 8),
                   axis.title.y = element_text(size = 8),
                   axis.text.y  = element_text(size = 8),
                   legend.position = "none")
plt

ingrese la descripción de la imagen aquí

Andrej
fuente
1
(+1) ¡Buena trama! ¿Quizás desee eliminar al menos algunos de los extractos de código de su pregunta para mejorar la legibilidad? Depende de usted, por supuesto.
ameba
Este código no es reproducible. Se puede introducir variables x, intercepty slope?
Roman Luštrik
Fijo; ahora funciona.
Andrej
hola, ¿por qué no estamos usando el segundo discriminante?
con gafas el