@export
def dbcluster_events(data: Any, cluster_columns: List[Any]=None, verbose: bool=False, normalize: bool=True, time_column: str='TimeCreatedUtc', max_cluster_distance: float=0.01, min_cluster_samples: int=2, **kwargs) -> Tuple[(pd.DataFrame, DBSCAN, np.ndarray)]:
    "\n    Cluster data set according to cluster_columns features.\n\n    Parameters\n    ----------\n    data : Any\n        Input data as a pandas DataFrame or numpy array\n    cluster_columns : List[Any], optional\n        List of columns to use for features\n        - for DataFrame this is a list of column names\n        - for numpy array this is a list of column indexes\n    verbose : bool, optional\n        Print additional information about clustering results (the default is False)\n    normalize : bool, optional\n        Normalize the input data (should probably always be True)\n    time_column : str, optional\n        If there is a time column the output data will be ordered by this\n        (the default is 'TimeCreatedUtc')\n    max_cluster_distance : float, optional\n        DBSCAN eps (max cluster member distance) (the default is 0.01)\n    min_cluster_samples : int, optional\n        DBSCAN min_samples (the minimum cluster size) (the default is 2)\n\n    Other Parameters\n    ----------------\n    kwargs: Other arguments are passed to DBSCAN constructor\n\n    Returns\n    -------\n    Tuple[pd.DataFrame, DBSCAN, np.ndarray]\n        Output dataframe with clustered rows\n        DBSCAN model\n        Normalized data set\n\n    "
    allowed_types = [np.ndarray, pd.DataFrame]
    x_input = None
    if isinstance(data, pd.DataFrame):
        if (cluster_columns is None):
            x_input = data.values
        else:
            x_input = data[cluster_columns].values
    elif isinstance(data, np.ndarray):
        x_input = (data if (cluster_columns is None) else data[:, cluster_columns].values)
    if (x_input is None):
        mssg = 'Input data not in expected format.\n{} is not one of allowed types {}'
        type_list = ', '.join((str(t) for t in allowed_types))
        mssg = mssg.format(str(type(data)), type_list)
        raise ValueError(mssg)
    db_cluster = DBSCAN(eps=max_cluster_distance, min_samples=min_cluster_samples, **kwargs)
    x_norm = (Normalizer().fit_transform(x_input) if normalize else x_input)
    db_cluster.fit(x_norm)
    labels = db_cluster.labels_
    (cluster_set, counts) = np.unique(labels, return_counts=True)
    if verbose:
        print('Clustering for set size ', len(x_norm), ' - ', len(cluster_set), ' clusters')
        print('Individual cluster sizes: ', ', '.join((str(c) for c in counts)))
    clustered_events = _merge_clustered_items(cluster_set, labels, data, time_column, counts)
    if verbose:
        print('Cluster output rows: ', len(clustered_events))
    return (clustered_events, db_cluster, x_norm)
Cluster data set according to cluster_columns features.

Parameters
----------
data : Any
    Input data as a pandas DataFrame or numpy array
cluster_columns : List[Any], optional
    List of columns to use for features
    - for DataFrame this is a list of column names
    - for numpy array this is a list of column indexes
verbose : bool, optional
    Print additional information about clustering results (the default is False)
normalize : bool, optional
    Normalize the input data (should probably always be True)
time_column : str, optional
    If there is a time column the output data will be ordered by this
    (the default is 'TimeCreatedUtc')
max_cluster_distance : float, optional
    DBSCAN eps (max cluster member distance) (the default is 0.01)
min_cluster_samples : int, optional
    DBSCAN min_samples (the minimum cluster size) (the default is 2)

Other Parameters
----------------
kwargs: Other arguments are passed to DBSCAN constructor

Returns
-------
Tuple[pd.DataFrame, DBSCAN, np.ndarray]
    Output dataframe with clustered rows
    DBSCAN model
    Normalized data set
@export
def dbcluster_events(data: Any, cluster_columns: List[Any]=None, verbose: bool=False, normalize: bool=True, time_column: str='TimeCreatedUtc', max_cluster_distance: float=0.01, min_cluster_samples: int=2, **kwargs) -> Tuple[(pd.DataFrame, DBSCAN, np.ndarray)]:
    "\n    Cluster data set according to cluster_columns features.\n\n    Parameters\n    ----------\n    data : Any\n        Input data as a pandas DataFrame or numpy array\n    cluster_columns : List[Any], optional\n        List of columns to use for features\n        - for DataFrame this is a list of column names\n        - for numpy array this is a list of column indexes\n    verbose : bool, optional\n        Print additional information about clustering results (the default is False)\n    normalize : bool, optional\n        Normalize the input data (should probably always be True)\n    time_column : str, optional\n        If there is a time column the output data will be ordered by this\n        (the default is 'TimeCreatedUtc')\n    max_cluster_distance : float, optional\n        DBSCAN eps (max cluster member distance) (the default is 0.01)\n    min_cluster_samples : int, optional\n        DBSCAN min_samples (the minimum cluster size) (the default is 2)\n\n    Other Parameters\n    ----------------\n    kwargs: Other arguments are passed to DBSCAN constructor\n\n    Returns\n    -------\n    Tuple[pd.DataFrame, DBSCAN, np.ndarray]\n        Output dataframe with clustered rows\n        DBSCAN model\n        Normalized data set\n\n    "
    allowed_types = [np.ndarray, pd.DataFrame]
    x_input = None
    if isinstance(data, pd.DataFrame):
        if (cluster_columns is None):
            x_input = data.values
        else:
            x_input = data[cluster_columns].values
    elif isinstance(data, np.ndarray):
        x_input = (data if (cluster_columns is None) else data[:, cluster_columns].values)
    if (x_input is None):
        mssg = 'Input data not in expected format.\n{} is not one of allowed types {}'
        type_list = ', '.join((str(t) for t in allowed_types))
        mssg = mssg.format(str(type(data)), type_list)
        raise ValueError(mssg)
    db_cluster = DBSCAN(eps=max_cluster_distance, min_samples=min_cluster_samples, **kwargs)
    x_norm = (Normalizer().fit_transform(x_input) if normalize else x_input)
    db_cluster.fit(x_norm)
    labels = db_cluster.labels_
    (cluster_set, counts) = np.unique(labels, return_counts=True)
    if verbose:
        print('Clustering for set size ', len(x_norm), ' - ', len(cluster_set), ' clusters')
        print('Individual cluster sizes: ', ', '.join((str(c) for c in counts)))
    clustered_events = _merge_clustered_items(cluster_set, labels, data, time_column, counts)
    if verbose:
        print('Cluster output rows: ', len(clustered_events))
    return (clustered_events, db_cluster, x_norm)