code: def solve_normal_eqn(
      key: Tuple,
      key_pattern: List[str],
      pdf: pd.DataFrame,
      labeldf: pd.DataFrame,
      alphas: Dict[str, Float],
      covdf: pd.DataFrame,
  ) -> pd.DataFrame:
      """
      This function assembles the matrices XtX and XtY for a particular sample_block (where the contribution of that sample_block
      has been omitted) and solves the equation [(XtX + I*alpha)]-1 * XtY = B for a list of alpha values, and returns the
      coefficient matrix B, where B has 1 row per header in the block X and 1 column per combination of alpha value and
      label.
  
      Args:
          key : unique key identifying the group of rows emitted by a groupBy statement
          key_pattern : pattern of columns used in the groupBy statement that emitted this group of rows
          pdf : starting Pandas DataFrame containing the lists of rows from XtX and XtY for block X identified by :key:
              schema (specified by the normal_eqn_struct):
               |-- header_block: string
               |-- sample_block: string
               |-- label: string
               |-- header: string
               |-- sort_key: integer
               |-- xtx: array
               |    |-- element: double
               |-- xty: array
               |    |-- element: double
          labeldf : Pandas DataFrame containing label values (i. e., the Y in the normal equation above).
          alphas : dict of {alphaName : alphaValue} for the alpha values to be used
          covdf: Pandas DataFrame containing covariates that should be included with every block X above (can be empty).
  
      Returns:
          transformed Pandas DataFrame containing the coefficient matrix B
              schema (specified by the model_struct):
                   |-- header_block: string
                   |-- sample_block: string
                   |-- header: string
                   |-- sort_key: integer
                   |-- alphas: array
                   |    |-- element: string
                   |-- labels: array
                   |    |-- element: string
                   |-- coefficients: array
                   |    |-- element: double
      """
  
      (
          header_block,
          sample_block,
          label,
      ) = parse_header_block_sample_block_label(key, key_pattern)
      sort_in_place(pdf, ["sort_key", "header"])
      alpha_names, alpha_values = zip(*sorted(alphas.items()))
      if covdf.empty:
          beta_stack = evaluate_coefficients(pdf, alpha_values, 0)
      else:
          beta_stack = evaluate_coefficients(
              pdf, alpha_values, len(covdf.columns)
          )
      row_indexer = cross_alphas_and_labels(alpha_names, labeldf, label)
      alpha_row, label_row = zip(*row_indexer)
      output_length = len(pdf)
      data = {
          "header_block": header_block,
          "sample_block": sample_block,
          "header": pdf["header"],
          "sort_key": pdf["sort_key"],
          "alphas": [list(alpha_row)] * output_length,
          "labels": [list(label_row)] * output_length,
          "coefficients": list(beta_stack),
      }
  
      return pd.DataFrame(data)
  
file_path: glow/python/glow/wgr/ridge_udfs.py
imports: from glow.wgr.model_functions import *
  from nptyping import Float
  import pandas
  from pyspark.sql.types import ArrayType, IntegerType, StructType, StructField, StringType, DoubleType
  from typeguard import typechecked
  from typing import Dict, List
label_desc: Use image node_id 3 for calling a global function with example usage: solve_normal_eqn(key, key_pattern, pdf, labeldf, alphas, covdf) and returns: pd