def generate_toymc(data, size, knn=4, power=2.0,
                   reweighting_iterations=5, sample_weight=None, random_state=numpy.random):
    """Generates toy Monte-Carlo, the dataset with distribution very close to the original one.

    :type data: numpy.array | pandas.DataFrame, the original distribution
    :type size: int, the number of events to generate
    :type knn: int | None, how many neighbours should we consider
    :type power: float, instead of uniform distribution, makes the point to tend to one of initial points
        (the greater, the closer to first point)
    :type reweighting_iterations: int, an iterative algorithm is used, which changes the probabilities
        so that all the points have equal probability to be chosen as neighbour
    :rtype: (pandas.DataFrame, int), returns the generated toymc and the number of events
        that were simply copied from original data set.
    """

    data = pandas.DataFrame(data)
    input_length = len(data)

    sample_weight = check_sample_weight(data, sample_weight=sample_weight)
    sample_weight /= numpy.sum(sample_weight)

    if input_length <= 2:
        # unable to generate new events with only one-two given
        return data, len(data)

    assert knn > 0, "knn should be positive"

    # generating knn
    neighbors_helper = NearestNeighbors(n_neighbors=knn, algorithm='ball_tree', )
    neighbors_helper.fit(data)
    neighbours = neighbors_helper.kneighbors(data, return_distance=False)[:, 1:]

    secondary_weights = numpy.ones(len(neighbours), dtype=float)
    for _ in range(reweighting_iterations):
        probabilities = _count_probabilities(sample_weight, secondary_weights, neighbours)
        secondary_weights *= ((sample_weight / probabilities) ** 0.5)

    # generating indices and weights
    k_1 = random_state.choice(input_length, p=sample_weight, size=size)
    k_2 = numpy.zeros(size, dtype=int)

    # drawing random neighbours
    for i, first_neighbour in enumerate(k_1):
        neighs = neighbours[first_neighbour]
        neigh_weights = numpy.take(secondary_weights, neighs)
        neigh_weights /= numpy.sum(neigh_weights)
        k_2[i] = random_state.choice(neighs, p=neigh_weights)

    numpied_df = data.values
    t_1 = 0.6 * random_state.random(size) ** power
    t_2 = 1. - t_1

    new_data = t_1[:, numpy.newaxis] * numpied_df[k_1, :] + t_2[:, numpy.newaxis] * numpied_df[k_2, :]
    return pandas.DataFrame(new_data, columns=data.columns), 0
dataset/ETHPy150Open anaderi/lhcb_trigger_ml/hep_ml/toymc.py/generate_toymc/original