"""

"""
import statistics
import logging


def inverted_distance_weight(temperatures, distances, p):
    """
    
    :param temperatures: The temperatures
    :param distances: The distances (in m)
    :param p: The power, normally 2 or 3
    :return: interpolated temperature
    """
    inverted_sum_distances = sum([distance ** -p for distance in distances])
    weights = [(distance ** -p) / inverted_sum_distances for distance in distances]
    temperature_idw = sum([w * t_i for w, t_i in zip(weights, temperatures)])
    return temperature_idw


def get_square_error_calculator(t_actual):
    """
    
    :param t_actual: The actual temperature
    :return: function to calculate the square error given the estimated temperature
    :rtype: lambda
    """
    def calculate_square_error(t_estimated):
        return (t_estimated - t_actual) ** 2
    return calculate_square_error


def get_interpolation_result_for_some_neighbours(temperature_distance_tuples, t_actual, postfix=""):
    """
    
    :param temperature_distance_tuples: List of temperature and distance pairs
    :param t_actual: The actual temperature
    :param postfix: The postfix for different methods if needed
    :return: Several simplistic measurements.
    :rtype: dict
    """
    if not temperature_distance_tuples:  # No neighbours could be found
        return {}
    temperatures, distances = zip(*temperature_distance_tuples)
    calculate_square_error = get_square_error_calculator(t_actual)
    result = {
        "idw_p2" + postfix: calculate_square_error(inverted_distance_weight(temperatures, distances, 2)),
        "idw_p3" + postfix: calculate_square_error(inverted_distance_weight(temperatures, distances, 3)),
        "max" + postfix: calculate_square_error(max(temperatures)),
        "median" + postfix: calculate_square_error(statistics.median(temperatures)),
        "min" + postfix: calculate_square_error(min(temperatures))
    }

    return result


def get_interpolation_result_for_all_neighbours(temperature_distance_tuples, t_actual):
    """

    :param temperature_distance_tuples: List of temperature and distance pairs
    :param t_actual: The actual temperature
    :param postfix: The postfix for different methods if needed
    :return: Several simplistic measurements.
    :rtype: dict
    """
    if not temperature_distance_tuples:  # No neighbours could be found
        return {}
    temperatures, distances = zip(*temperature_distance_tuples)
    calculate_square_error = get_square_error_calculator(t_actual)
    result = {
        "idw_p2_all": calculate_square_error(inverted_distance_weight(temperatures, distances, 2)),
        "idw_p3_all": calculate_square_error(inverted_distance_weight(temperatures, distances, 3)),
    }
    return result


def demo():
    start_date = '2016-01-01T00:00'
    end_date = '2016-03-31T23:59'
    from filter_weather_data.filters import StationRepository
    from .nearest_k_finder import NearestKFinder
    station_repository = StationRepository()
    station_dicts = station_repository.load_all_stations(start_date, end_date, limit=20)
    chosen_index = 9
    search_for = station_dicts[chosen_index]
    print("picked", station_dicts[chosen_index]["name"], "to look for")
    del station_dicts[chosen_index]  # otherwise triangles will contain the searched point as well.
    k_nearest_finder = NearestKFinder(station_dicts, start_date, end_date)
    t = search_for["data_frame"].index.values[0]
    neighbours = k_nearest_finder.find_k_nearest_neighbours(search_for, t, 3)
    t_actual = search_for["data_frame"].loc[t].temperature
    result = get_interpolation_result_for_some_neighbours(neighbours, t_actual)
    neighbours = k_nearest_finder.find_k_nearest_neighbours(search_for, t, -1)
    result.update(get_interpolation_result_for_all_neighbours(neighbours, t_actual))
    print("actual measurement:", t_actual)
    for neighbour in neighbours:
        temperature, distance = neighbour
        print("measured", temperature, "°C in", distance, "meters distance")
    for method, value in result.items():
        print("method", method, "value", value**.5)

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    demo()

@@ -1,13 +1,131 @@
 %22%22%22%0A%0A
+Run demo with%0Apython3 -m interpolation.interpolator.statistical_interpolator interpolator/statistical_interpolator.py%0A
 %22%22%22%0Aimpo
@@ -1031,35 +1031,16 @@
 n_result
-_for_some_neighbour
 s(temper
@@ -1800,24 +1800,130 @@
 ances, 3)),%0A
+        %22idw_p4%22 + postfix: calculate_square_error(inverted_distance_weight(temperatures, distances, 4)),%0A
         %22max
@@ -2133,833 +2133,97 @@
 es))
+,
 %0A    
-%7D%0A%0A    return result%0A%0A%0Adef get_interpolation_result_for_all_neighbours(temperature_distance_tuples, t_actual):%0A    %22%22%22%0A%0A    :param temperature_distance_tuples: List of temperature and distance pairs%0A    :param t_actual: The actual temperature%0A    :param postfix: The postfix for different methods if needed%0A    :return: Several simplistic measurements.%0A    :rtype: dict%0A    %22%22%22%0A    if not temperature_distance_tuples:  # No neighbours could be found%0A        return %7B%7D%0A    temperatures, distances = zip(*temperature_distance_tuples)%0A    calculate_square_error = get_square_error_calculator(t_actual)%0A    result = %7B%0A        %22idw_p2_all%22: calculate_square_error(inverted_distance_weight(temperatures, distances, 2)),%0A        %22idw_p3_all%22: calculate_square_error(inverted_distance_weight(temperatures, distances, 3
+    %22mean%22 + postfix: calculate_square_error(statistics.mean(temperatures
 ))
-,
 %0A    %7D%0A
+%0A
     
@@ -3105,27 +3105,8 @@
 sult
-_for_some_neighbour
 s(ne
@@ -3250,26 +3250,8 @@
 sult
-_for_all_neighbour
 s(ne

change output