code: def from_pandas_lasso(
      X: pd.DataFrame,
      beta: float,
      max_iter: int = 100,
      h_tol: float = 1e-8,
      w_threshold: float = 0.0,
      tabu_edges: List[Tuple[str, str]] = None,
      tabu_parent_nodes: List[str] = None,
      tabu_child_nodes: List[str] = None,
  ) -> StructureModel:
      """
      Learn the `StructureModel`, the graph structure with lasso regularisation
      describing conditional dependencies between variables in data presented as a pandas dataframe.
  
      Based on DAGs with NO TEARS.
      @inproceedings{zheng2018dags,
          author = {Zheng, Xun and Aragam, Bryon and Ravikumar, Pradeep and Xing, Eric P.},
          booktitle = {Advances in Neural Information Processing Systems},
          title = {{DAGs with NO TEARS: Continuous Optimization for Structure Learning}},
          year = {2018},
          codebase = {https://github.com/xunzheng/notears}
      }
  
      Args:
          X: input data.
          beta: Constant that multiplies the lasso term.
          max_iter: max number of dual ascent steps during optimisation.
          h_tol: exit if h(W) < h_tol (as opposed to strict definition of 0).
          w_threshold: fixed threshold for absolute edge weights.
          tabu_edges: list of edges(from, to) not to be included in the graph.
          tabu_parent_nodes: list of nodes banned from being a parent of any other nodes.
          tabu_child_nodes: list of nodes banned from being a child of any other nodes.
  
      Returns:
           StructureModel: graph of conditional dependencies between data variables.
  
      Raises:
          ValueError: If X does not contain data.
      """
  
      data = deepcopy(X)
  
      non_numeric_cols = data.select_dtypes(exclude="number").columns
  
      if not non_numeric_cols.empty:
          raise ValueError(
              "All columns must have numeric data. "
              f"Consider mapping the following columns to int {non_numeric_cols}"
          )
  
      col_idx = {c: i for i, c in enumerate(data.columns)}
      idx_col = {i: c for c, i in col_idx.items()}
  
      if tabu_edges:
          tabu_edges = [(col_idx[u], col_idx[v]) for u, v in tabu_edges]
      if tabu_parent_nodes:
          tabu_parent_nodes = [col_idx[n] for n in tabu_parent_nodes]
      if tabu_child_nodes:
          tabu_child_nodes = [col_idx[n] for n in tabu_child_nodes]
  
      g = from_numpy_lasso(
          data.values,
          beta,
          max_iter,
          h_tol,
          w_threshold,
          tabu_edges,
          tabu_parent_nodes,
          tabu_child_nodes,
      )
  
      sm = StructureModel()
      sm.add_nodes_from(data.columns)
      sm.add_weighted_edges_from(
          [
              (idx_col[u], idx_col[v], w)
              for u, v, w in g.edges.data("weight")
          ],
          origin="learned",
      )
  
      return sm
  
file_path: causalnex/causalnex/structure/notears.py
imports: import logging
  import warnings
  from copy import deepcopy
  from typing import List, Tuple
  import numpy
  import pandas
  import scipy.linalg
  import scipy.optimize
  from causalnex.structure.structuremodel import StructureModel
label_desc: Use image node_id 4 for calling a global function with example usage: from_pandas_lasso(X, beta, max_iter, h_tol, w_threshold, tabu_edges, tabu_parent_nodes, tabu_child_nodes) and returns: sm