code: def from_pandas_dynamic(  # pylint: disable=too-many-arguments
      time_series: Union[pd.DataFrame, List[pd.DataFrame]],
      p: int,
      lambda_w: float = 0.1,
      lambda_a: float = 0.1,
      max_iter: int = 100,
      h_tol: float = 1e-8,
      w_threshold: float = 0.0,
      tabu_edges: List[Tuple[int, int, int]] = None,
      tabu_parent_nodes: List[int] = None,
      tabu_child_nodes: List[int] = None,
  ) -> StructureModel:
      """
      Learn the graph structure of a Dynamic Bayesian Network describing conditional dependencies between variables in
      data. The input data is a time series or a list of realisations of a same time series.
      The optimisation is to minimise a score function F(W, A) over the graph's contemporaneous (intra-slice) weighted
      adjacency matrix, W, and lagged (inter-slice) weighted adjacency matrix, A, subject to the a constraint function
      h(W), where h_value(W) == 0 characterises an acyclic graph. h(W) > 0 is a continuous, differentiable function that
      encapsulated how acyclic the graph is (less = more acyclic).
  
      Based on "DYNOTEARS: Structure Learning from Time-Series Data".
      https://arxiv.org/abs/2002.00498
      @inproceedings{pamfil2020dynotears,
          title={DYNOTEARS: Structure Learning from Time-Series Data},
          author={Pamfil, Roxana and Sriwattanaworachai, Nisara and Desai, Shaan and Pilgerstorfer,
          Philip and Georgatzis, Konstantinos and Beaumont, Paul and Aragam, Bryon},
          booktitle={International Conference on Artificial Intelligence and Statistics},
          pages={1595--1605},
          year={2020}year={2020},
      }
      Args:
          time_series: pd.DataFrame or List of pd.DataFrame instances.
          If a list is provided each element of the list being an realisation of a time series (i.e. time series governed
          by the same processes)
          The columns of the data frame represent the variables in the model, and the *index represents the time index*.
          Successive events, therefore, must be indexed with one integer of difference between them too.
          p: Number of past interactions we allow the model to create. The state of a variable at time `t` is affected by
          past variables up to a `t-p`, as well as by other variables at `t`.
          lambda_w: parameter for l1 regularisation of intra-slice edges
          lambda_a: parameter for l1 regularisation of inter-slice edges
          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(lag, from, to) not to be included in the graph. `lag == 0` implies that the edge is
          forbidden in the INTRA graph (W), while lag > 0 implies an INTER-slice weight equal zero.
          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 representing the model learnt. The node names are noted as `{var}_lag{l}`, where `var` is the
          original variable name as in the give in the input data frames and `l`, in 0,1,2..p is the correspondent
          time lag.
      """
      time_series = (
          [time_series]
          if not isinstance(time_series, list)
          else time_series
      )
  
      X, Xlags = DynamicDataTransformer(p=p).fit_transform(
          time_series, return_df=False
      )
  
      col_idx = {c: i for i, c in enumerate(time_series[0].columns)}
      idx_col = {i: c for c, i in col_idx.items()}
  
      if tabu_edges:
          tabu_edges = [
              (lag, col_idx[u], col_idx[v]) for lag, 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_dynamic(
          X,
          Xlags,
          lambda_w,
          lambda_a,
          max_iter,
          h_tol,
          w_threshold,
          tabu_edges,
          tabu_parent_nodes,
          tabu_child_nodes,
      )
  
      sm = StructureModel()
      sm.add_nodes_from(
          [
              f"{var}_lag{l_val}"
              for var in col_idx.keys()
              for l_val in range(p + 1)
          ]
      )
      sm.add_weighted_edges_from(
          [
              (
                  _format_name_from_pandas(idx_col, u),
                  _format_name_from_pandas(idx_col, v),
                  w,
              )
              for u, v, w in g.edges.data("weight")
          ],
          origin="learned",
      )
  
      return sm
  
file_path: causalnex/causalnex/structure/dynotears.py
imports: import warnings
  from typing import Dict, List, Tuple, Union
  import numpy
  import pandas
  import scipy.linalg
  import scipy.optimize
  from causalnex.structure import StructureModel
  from causalnex.structure.transformers import DynamicDataTransformer
label_desc: Use image node_id 1 for calling a global function with example usage: from_pandas_dynamic(time_series, p, lambda_w, lambda_a, max_iter, h_tol, w_threshold, tabu_edges, tabu_parent_nodes, tabu_child_nodes) and returns: sm