code: def estimate_row_scales(
              self,
              X_centered,
              column_scales):
          
          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)
docs: row_scale[i]**2 =
          mean{j in observed[i, :]}{
              (X[i, j] - row_center[i] - column_center[j]) ** 2
              --------------------------------------------------
                          column_scale[j] ** 2
          }