@@ -596,8 +596,8 @@ add_null_effect <- function(model_init, V) {
596596# and log Bayes factor calculations.
597597#
598598# Functions: compute_eigen_decomposition, add_eigen_decomposition,
599- # compute_omega_quantities, compute_theta_blup, lbf_stabilization,
600- # compute_posterior_weights, compute_lbf_gradient
599+ # compute_omega_quantities, scale_design_matrix, compute_theta_blup,
600+ # lbf_stabilization, compute_posterior_weights, compute_lbf_gradient
601601# =============================================================================
602602
603603# Compute eigenvalue decomposition for unmappable methods
@@ -617,19 +617,6 @@ compute_eigen_decomposition <- function(XtX, n) {
617617# Add eigen decomposition to ss data objects for unmappable methods
618618# ' @keywords internal
619619add_eigen_decomposition <- function (data , params , individual_data = NULL ) {
620- # Standardize y to unit variance for all unmappable effects methods
621- y_scale_factor <- 1
622-
623- if (params $ unmappable_effects != " none" ) {
624- var_y <- data $ yty / (data $ n - 1 )
625- if (abs(var_y - 1 ) > 1e-10 ) {
626- sd_y <- sqrt(var_y )
627- data $ yty <- data $ yty / var_y
628- data $ Xty <- data $ Xty / sd_y
629- y_scale_factor <- sd_y
630- }
631- }
632-
633620 # Compute eigen decomposition
634621 eigen_decomp <- compute_eigen_decomposition(data $ XtX , data $ n )
635622
@@ -638,19 +625,47 @@ add_eigen_decomposition <- function(data, params, individual_data = NULL) {
638625 data $ eigen_values <- eigen_decomp $ Dsq
639626 data $ VtXty <- t(eigen_decomp $ V ) %*% data $ Xty
640627
641- # SuSiE.ash requires the X matrix and standardized y vector
642628 if (params $ unmappable_effects == " ash" ) {
643629 if (is.null(individual_data )) {
644630 stop(" Adaptive shrinkage (ash) requires individual-level data" )
645631 }
646- data $ X <- individual_data $ X
647- data $ y <- individual_data $ y / y_scale_factor
648- data $ VtXt <- t(data $ eigen_vectors ) %*% t(individual_data $ X )
632+
633+ X_scaled <- scale_design_matrix(
634+ individual_data $ X ,
635+ center = attr(individual_data $ X , " scaled:center" ),
636+ scale = attr(individual_data $ X , " scaled:scale" )
637+ )
638+
639+ data $ X <- X_scaled
640+ data $ y <- individual_data $ y
641+ data $ VtXt <- t(data $ eigen_vectors ) %*% t(X_scaled )
649642 }
650643
651644 return (data )
652645}
653646
647+ # ' Scale design matrix using centering and scaling parameters
648+ # '
649+ # ' Applies column-wise centering and scaling to match the space used by
650+ # ' compute_XtX() and compute_Xty() for unmappable effects methods.
651+ # '
652+ # ' @param X Matrix to scale (n × p)
653+ # ' @param center Vector of column means to subtract (length p), or NULL
654+ # ' @param scale Vector of column SDs to divide by (length p), or NULL
655+ # '
656+ # ' @return Scaled matrix with centered and scaled columns
657+ # '
658+ # ' @keywords internal
659+ scale_design_matrix <- function (X , center = NULL , scale = NULL ) {
660+ if (is.null(center )) center <- rep(0 , ncol(X ))
661+ if (is.null(scale )) scale <- rep(1 , ncol(X ))
662+
663+ X_centered <- sweep(X , 2 , center , " -" )
664+ X_scaled <- sweep(X_centered , 2 , scale , " /" )
665+
666+ return (X_scaled )
667+ }
668+
654669# Compute Omega-weighted quantities for unmappable effects methods
655670# ' @keywords internal
656671compute_omega_quantities <- function (data , tau2 , sigma2 ) {
0 commit comments