class_docstr: Iterative estimation of row and column centering/scaling
  using the algorithm from page 31 of:
      Matrix Completion and Low-Rank SVD via Fast Alternating Least Squares
docstr: row_scale[i]**2 =
  mean{j in observed[i, :]}{
      (X[i, j] - row_center[i] - column_center[j]) ** 2
      --------------------------------------------------
                  column_scale[j] ** 2
  }
docstr_tok: ["row_scale","[","i","]","*","*","2","=","mean","{","j","in","observed","[","i",",",":","]","}","{","(","X","[","i",",","j","]","-","row_center","[","i","]","-","column_center","[","j","]",")","*","*","2","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","column_scale","[","j","]","*","*","2","}"]
code: def estimate_row_scales(self, X_centered, column_scales):
      """
      row_scale[i]**2 =
      mean{j in observed[i, :]}{
          (X[i, j] - row_center[i] - column_center[j]) ** 2
          --------------------------------------------------
                      column_scale[j] ** 2
      }
      """
      n_rows, n_cols = X_centered.shape
      column_scales = np.asarray(column_scales)
      if len(column_scales) != n_cols:
          raise ValueError(
              "Expected length %d but got shape %s"
              % (n_cols, column_scales)
          )
      row_variances = np.nanmean(
          X_centered**2 / (column_scales**2).reshape((1, n_cols)),
          axis=1,
      )
      row_variances[row_variances == 0] = 1.0
      assert len(row_variances) == n_rows, "%d != %d" % (
          len(row_variances),
          n_rows,
      )
      return np.sqrt(row_variances)
  
imports: import numpy
label_desc: Use image node_id 6 for calling the BiScaler obj's underlying member method code with example usage: obj.estimate_row_scales(X_centered, column_scales) and returns: np