#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  : knn.py
# @Time      : 2020/9/25 12:29
# @Author    : 陈嘉昕
# @Demand    : k-临近算法，和训练的模型作比较


import csv
import math
import operator
from random import shuffle
import matplotlib.pyplot as plt

# 数据集
training_set = []
# 测试集
test_set = []


def cross_validation(file_name):
    k_max = len(training_set) - 1
    k_scores = []
    for k in range(1, k_max):
        acc = 0
        for i in range(k_max):
            to_predict = training_set[i]
            training_set.remove(to_predict)
            predictions = fit([to_predict], training_set, k)
            acc += calculate_accuracy([to_predict], predictions)
            training_set.insert(i, to_predict)

        scores = acc / k_max
        print("k =", repr(k), "  accuracy = " + repr(scores))
        k_scores.append(scores)

    plt.plot(range(1, k_max), k_scores)
    plt.xlabel('Value of K')
    plt.ylabel('Accuracy')
    plt.savefig(file_name)
    plt.show()
    max_index, max_number = max(enumerate(k_scores), key=operator.itemgetter(1))
    print("\n\nThe best results: k =", repr(max_index + 1), ", accuracy = " + repr(max_number) + "\n\n")


def load_dataset(filename, training=False):
    # 打开文件
    with open(filename, 'rt') as camile:
        next(csv.reader(camile))
        lines = csv.reader(camile)
        dataset = list(lines)

        shuffle(dataset)

        if training:
            split = 0.8 * len(dataset)
        else:
            split = len(dataset)

        for x in range(len(dataset)):
            for y in range(4):
                dataset[x][y] = float(dataset[x][y])
            if len(training_set) <= split:
                training_set.append(dataset[x])
            else:
                test_set.append(dataset[x])


def euclidean_distance(instance1, instance2, number_of_params):
    distance = 0
    for param in range(number_of_params):
        distance += pow((float(instance1[param]) - float(instance2[param])), 2)
    return math.sqrt(distance)


def get_neighbors(trainingSet, instance, k):
    distances = []
    length = len(instance) - 1
    for x in range(len(trainingSet)):
        dist = euclidean_distance(instance, trainingSet[x], length)
        distances.append((trainingSet[x], dist))
    distances.sort(key=operator.itemgetter(1))
    neighbors = []
    for x in range(k):
        neighbors.append(distances[x][0])
    return neighbors


def calculate_votes(neighbors):
    class_votes = {}
    for i in range(len(neighbors)):
        response = neighbors[i][-1]
        if response in class_votes:
            class_votes[response] += 1
        else:
            class_votes[response] = 1
    sorted_votes = sorted(class_votes.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_votes[0][0]


def calculate_accuracy(testSet, predictions):
    correct = 0
    for x in range(len(testSet)):
        if testSet[x][-1] == predictions[x]:
            correct += 1
    return (correct / float(len(testSet))) * 100.0


def fit(to_predict, dataset, k):
    predictions = []
    for x in range(len(to_predict)):
        neighbors = get_neighbors(dataset, to_predict[x], k)
        result = calculate_votes(neighbors)
        predictions.append(result)

    return predictions


def predict(to_predict, data_set_path, k=12, training=False):
    if len(training_set) == 0:
        load_dataset(data_set_path, training)

    if training:
        predictions = fit(test_set, training_set, k)
        accuracy = calculate_accuracy(test_set, predictions)
        print('Accuracy: ' + repr(accuracy) + '%')
    else:
        predictions = fit(to_predict, training_set, k)

    return predictions


def run_one():
    training_set.clear()
    test_set.clear()
    load_dataset("data/video_data_for_lie_training.csv", True)
    cross_validation("image/knn_model_1.png")


def run_two():
    training_set.clear()
    test_set.clear()
    load_dataset("data/audio_data_for_lie_training.csv", True)
    cross_validation("image/knn_model_2.png")

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  : knn.py
# @Time      : 2020/9/25 12:29
# @Author    : 陈嘉昕
# @Demand    : k-临近算法，和训练的模型作比较


import csv
import math
import operator
from random import shuffle
import matplotlib.pyplot as plt

# 数据集
training_set = []
# 测试集
test_set = []


def cross_validation(file_name):
    k_max = len(training_set) - 1
    k_scores = []
    for k in range(1, k_max):
        acc = 0
        for i in range(k_max):
            to_predict = training_set[i]
            training_set.remove(to_predict)
            predictions = fit([to_predict], training_set, k)
            acc += calculate_accuracy([to_predict], predictions)
            training_set.insert(i, to_predict)

        scores = acc / k_max
        print("k =", repr(k), "  accuracy = " + repr(scores))
        k_scores.append(scores)

    plt.plot(range(1, k_max), k_scores)
    plt.xlabel('Value of K')
    plt.ylabel('Accuracy')
    plt.savefig(file_name)
    plt.show()
    max_index, max_number = max(enumerate(k_scores), key=operator.itemgetter(1))
    print("\n\nThe best results: k =", repr(max_index + 1), ", accuracy = " + repr(max_number) + "\n\n")


def load_dataset(filename, training=False):
    # 打开文件
    with open(filename, 'rt') as camile:
        next(csv.reader(camile))
        lines = csv.reader(camile)
        dataset = list(lines)

        shuffle(dataset)

        if training:
            split = 0.8 * len(dataset)
        else:
            split = len(dataset)

        for x in range(len(dataset)):
            for y in range(4):
                dataset[x][y] = float(dataset[x][y])
            if len(training_set) <= split:
                training_set.append(dataset[x])
            else:
                test_set.append(dataset[x])


def euclidean_distance(instance1, instance2, number_of_params):
    distance = 0
    for param in range(number_of_params):
        distance += pow((float(instance1[param]) - float(instance2[param])), 2)
    return math.sqrt(distance)


def get_neighbors(trainingSet, instance, k):
    distances = []
    length = len(instance) - 1
    for x in range(len(trainingSet)):
        dist = euclidean_distance(instance, trainingSet[x], length)
        distances.append((trainingSet[x], dist))
    distances.sort(key=operator.itemgetter(1))
    neighbors = []
    for x in range(k):
        neighbors.append(distances[x][0])
    return neighbors


def calculate_votes(neighbors):
    class_votes = {}
    for i in range(len(neighbors)):
        response = neighbors[i][-1]
        if response in class_votes:
            class_votes[response] += 1
        else:
            class_votes[response] = 1
    sorted_votes = sorted(class_votes.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_votes[0][0]


def calculate_accuracy(testSet, predictions):
    correct = 0
    for x in range(len(testSet)):
        if testSet[x][-1] == predictions[x]:
            correct += 1
    return (correct / float(len(testSet))) * 100.0


def fit(to_predict, dataset, k):
    predictions = []
    for x in range(len(to_predict)):
        neighbors = get_neighbors(dataset, to_predict[x], k)
        result = calculate_votes(neighbors)
        predictions.append(result)

    return predictions


def predict(to_predict, data_set_path, k=12, training=False):
    if len(training_set) == 0:
        load_dataset(data_set_path, training)

    if training:
        predictions = fit(test_set, training_set, k)
        accuracy = calculate_accuracy(test_set, predictions)
        print('Accuracy: ' + repr(accuracy) + '%')
    else:
        predictions = fit(to_predict, training_set, k)

    return predictions


def run_one():
    training_set.clear()
    test_set.clear()
    load_dataset("data/video_data_for_lie_training.csv", True)
    cross_validation("image/knn_model_1.png")


def run_two():
    training_set.clear()
    test_set.clear()
    load_dataset("data/audio_data_for_lie_training.csv", True)
    cross_validation("image/knn_model_2.png")

#!/usr/bin/env python # -*- coding:utf-8 -*- # @FileName  : knn.py # @Time      : 2020/9/25 12:29 # @Author    : 陈嘉昕 # @Demand    : k-临近算法，和训练的模型作比较 # 数据集 # 测试集 # 打开文件