def from_pandas(X: pd.DataFrame, dist_type_schema: Dict[(Union[(str, int)], str)]=None, lasso_beta: float=0.0, ridge_beta: float=0.0, use_bias: bool=False, hidden_layer_units: Iterable[int]=None, max_iter: int=100, w_threshold: float=None, tabu_edges: List[Tuple[(str, str)]]=None, tabu_parent_nodes: List[str]=None, tabu_child_nodes: List[str]=None, **kwargs) -> StructureModel:
    "\n    Learn the `StructureModel`, the graph structure describing conditional dependencies between variables\n    in data presented as a pandas dataframe.\n\n    The optimisation is to minimise a score function :math:`F(W)` over the graph's\n    weighted adjacency matrix, :math:`W`, subject to the a constraint function :math:`h(W)`,\n    where :math:`h(W) == 0` characterises an acyclic graph.\n    :math:`h(W) > 0` is a continuous, differentiable function that encapsulated how acyclic the graph is\n    (less == more acyclic).\n    Full details of this approach to structure learning are provided in the publication:\n\n    Based on DAGs with NO TEARS.\n    @inproceedings{zheng2018dags,\n        author = {Zheng, Xun and Aragam, Bryon and Ravikumar, Pradeep and Xing, Eric P.},\n        booktitle = {Advances in Neural Information Processing Systems},\n        title = {{DAGs with NO TEARS: Continuous Optimization for Structure Learning}},\n        year = {2018},\n        codebase = {https://github.com/xunzheng/notears}\n    }\n\n    Args:\n        X: 2d input data, axis=0 is data rows, axis=1 is data columns. Data must be row oriented.\n\n        dist_type_schema: The dist type schema corresponding to the passed in data X.\n        It maps the pandas column name in X to the string alias of a dist type.\n        A list of alias names can be found in ``dist_type/__init__.py``.\n        If None, assumes that all data in X is continuous.\n\n        lasso_beta: Constant that multiplies the lasso term (l1 regularisation).\n        NOTE when using nonlinearities, the l1 loss only applies to the dag_layer.\n\n        use_bias: Whether to fit a bias parameter in the NOTEARS algorithm.\n\n        ridge_beta: Constant that multiplies the ridge term (l2 regularisation).\n        When using nonlinear layers use of this parameter is recommended.\n\n        hidden_layer_units: An iterable where its length determine the number of layers used,\n        and the numbers determine the number of nodes used for the layer in order.\n\n        w_threshold: fixed threshold for absolute edge weights.\n\n        max_iter: max number of dual ascent steps during optimisation.\n\n        tabu_edges: list of edges(from, to) not to be included in the graph.\n\n        tabu_parent_nodes: list of nodes banned from being a parent of any other nodes.\n\n        tabu_child_nodes: list of nodes banned from being a child of any other nodes.\n\n        **kwargs: additional arguments for NOTEARS MLP model\n\n    Returns:\n         StructureModel: graph of conditional dependencies between data variables.\n\n    Raises:\n        ValueError: If X does not contain data.\n    "
    data = deepcopy(X)
    dist_type_schema = (dist_type_schema if (dist_type_schema is None) else {X.columns.get_loc(col): alias for (col, alias) in dist_type_schema.items()})
    non_numeric_cols = data.select_dtypes(exclude='number').columns
    if (len(non_numeric_cols) > 0):
        raise ValueError('All columns must have numeric data. Consider mapping the following columns to int {non_numeric_cols}'.format(non_numeric_cols=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(X=data.values, dist_type_schema=dist_type_schema, lasso_beta=lasso_beta, ridge_beta=ridge_beta, use_bias=use_bias, hidden_layer_units=hidden_layer_units, w_threshold=w_threshold, max_iter=max_iter, tabu_edges=tabu_edges, tabu_parent_nodes=tabu_parent_nodes, tabu_child_nodes=tabu_child_nodes, **kwargs)
    sm = StructureModel()
    sm.add_nodes_from(data.columns)
    for (u, v, edge_dict) in g.edges.data(True):
        sm.add_edge(idx_col[u], idx_col[v], origin='learned', weight=edge_dict['weight'], mean_effect=edge_dict['mean_effect'])
    for (key, val) in g.graph.items():
        sm.graph[key] = val
    for node in g.nodes(data=True):
        node_name = idx_col[node[0]]
        sm.nodes[node_name]['bias'] = node[1]['bias']
    for node in g.nodes(data=True):
        node_name = idx_col[node[0]]
        sm.nodes[node_name]['dist_type'] = node[1]['dist_type']
    return sm
Learn the `StructureModel`, the graph structure describing conditional dependencies between variables
in data presented as a pandas dataframe.

The optimisation is to minimise a score function :math:`F(W)` over the graph's
weighted adjacency matrix, :math:`W`, subject to the a constraint function :math:`h(W)`,
where :math:`h(W) == 0` characterises an acyclic graph.
:math:`h(W) > 0` is a continuous, differentiable function that encapsulated how acyclic the graph is
(less == more acyclic).
Full details of this approach to structure learning are provided in the publication:

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: 2d input data, axis=0 is data rows, axis=1 is data columns. Data must be row oriented.

    dist_type_schema: The dist type schema corresponding to the passed in data X.
    It maps the pandas column name in X to the string alias of a dist type.
    A list of alias names can be found in ``dist_type/__init__.py``.
    If None, assumes that all data in X is continuous.

    lasso_beta: Constant that multiplies the lasso term (l1 regularisation).
    NOTE when using nonlinearities, the l1 loss only applies to the dag_layer.

    use_bias: Whether to fit a bias parameter in the NOTEARS algorithm.

    ridge_beta: Constant that multiplies the ridge term (l2 regularisation).
    When using nonlinear layers use of this parameter is recommended.

    hidden_layer_units: An iterable where its length determine the number of layers used,
    and the numbers determine the number of nodes used for the layer in order.

    w_threshold: fixed threshold for absolute edge weights.

    max_iter: max number of dual ascent steps during optimisation.

    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.

    **kwargs: additional arguments for NOTEARS MLP model

Returns:
     StructureModel: graph of conditional dependencies between data variables.

Raises:
    ValueError: If X does not contain data.
def from_pandas(X: pd.DataFrame, dist_type_schema: Dict[(Union[(str, int)], str)]=None, lasso_beta: float=0.0, ridge_beta: float=0.0, use_bias: bool=False, hidden_layer_units: Iterable[int]=None, max_iter: int=100, w_threshold: float=None, tabu_edges: List[Tuple[(str, str)]]=None, tabu_parent_nodes: List[str]=None, tabu_child_nodes: List[str]=None, **kwargs) -> StructureModel:
    "\n    Learn the `StructureModel`, the graph structure describing conditional dependencies between variables\n    in data presented as a pandas dataframe.\n\n    The optimisation is to minimise a score function :math:`F(W)` over the graph's\n    weighted adjacency matrix, :math:`W`, subject to the a constraint function :math:`h(W)`,\n    where :math:`h(W) == 0` characterises an acyclic graph.\n    :math:`h(W) > 0` is a continuous, differentiable function that encapsulated how acyclic the graph is\n    (less == more acyclic).\n    Full details of this approach to structure learning are provided in the publication:\n\n    Based on DAGs with NO TEARS.\n    @inproceedings{zheng2018dags,\n        author = {Zheng, Xun and Aragam, Bryon and Ravikumar, Pradeep and Xing, Eric P.},\n        booktitle = {Advances in Neural Information Processing Systems},\n        title = {{DAGs with NO TEARS: Continuous Optimization for Structure Learning}},\n        year = {2018},\n        codebase = {https://github.com/xunzheng/notears}\n    }\n\n    Args:\n        X: 2d input data, axis=0 is data rows, axis=1 is data columns. Data must be row oriented.\n\n        dist_type_schema: The dist type schema corresponding to the passed in data X.\n        It maps the pandas column name in X to the string alias of a dist type.\n        A list of alias names can be found in ``dist_type/__init__.py``.\n        If None, assumes that all data in X is continuous.\n\n        lasso_beta: Constant that multiplies the lasso term (l1 regularisation).\n        NOTE when using nonlinearities, the l1 loss only applies to the dag_layer.\n\n        use_bias: Whether to fit a bias parameter in the NOTEARS algorithm.\n\n        ridge_beta: Constant that multiplies the ridge term (l2 regularisation).\n        When using nonlinear layers use of this parameter is recommended.\n\n        hidden_layer_units: An iterable where its length determine the number of layers used,\n        and the numbers determine the number of nodes used for the layer in order.\n\n        w_threshold: fixed threshold for absolute edge weights.\n\n        max_iter: max number of dual ascent steps during optimisation.\n\n        tabu_edges: list of edges(from, to) not to be included in the graph.\n\n        tabu_parent_nodes: list of nodes banned from being a parent of any other nodes.\n\n        tabu_child_nodes: list of nodes banned from being a child of any other nodes.\n\n        **kwargs: additional arguments for NOTEARS MLP model\n\n    Returns:\n         StructureModel: graph of conditional dependencies between data variables.\n\n    Raises:\n        ValueError: If X does not contain data.\n    "
    data = deepcopy(X)
    dist_type_schema = (dist_type_schema if (dist_type_schema is None) else {X.columns.get_loc(col): alias for (col, alias) in dist_type_schema.items()})
    non_numeric_cols = data.select_dtypes(exclude='number').columns
    if (len(non_numeric_cols) > 0):
        raise ValueError('All columns must have numeric data. Consider mapping the following columns to int {non_numeric_cols}'.format(non_numeric_cols=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(X=data.values, dist_type_schema=dist_type_schema, lasso_beta=lasso_beta, ridge_beta=ridge_beta, use_bias=use_bias, hidden_layer_units=hidden_layer_units, w_threshold=w_threshold, max_iter=max_iter, tabu_edges=tabu_edges, tabu_parent_nodes=tabu_parent_nodes, tabu_child_nodes=tabu_child_nodes, **kwargs)
    sm = StructureModel()
    sm.add_nodes_from(data.columns)
    for (u, v, edge_dict) in g.edges.data(True):
        sm.add_edge(idx_col[u], idx_col[v], origin='learned', weight=edge_dict['weight'], mean_effect=edge_dict['mean_effect'])
    for (key, val) in g.graph.items():
        sm.graph[key] = val
    for node in g.nodes(data=True):
        node_name = idx_col[node[0]]
        sm.nodes[node_name]['bias'] = node[1]['bias']
    for node in g.nodes(data=True):
        node_name = idx_col[node[0]]
        sm.nodes[node_name]['dist_type'] = node[1]['dist_type']
    return sm