2016-02-02 8 views
3

Я пишу k ближайший классификатор соседей в python. Я столкнулся с проблемой, когда операции массива занимают слишком много времени.Как векторизовать операции массива в Python

def classify(k, train_data, target): 
    num_rows = train_data.shape[0] 
    num_cols = train_data.shape[1] 
    distances = [] 
    candidates = [0] * 10 

    for i, row in enumerate(train_data): 
     dist = euclidean_dist(target[:num_cols - 1], row[:num_cols - 1]) #slow 
     distances.append((dist, row[num_cols - 1])) 

    distances.sort(key=lambda tup: tup[0]) 
    distances = distances[:k] 

    for i, d in enumerate(distances): 
     candidates[d[1]] += 1 

    return candidates.index(max(candidates)) 

def euclidean_dist(x1, x2): 
    assert(len(x1) == len(x2)) 
    result = 0 

    pdb.set_trace() 
    for i in range(len(x1)): #culprit, x1 and x2 are both 256 length lists 
     result += math.pow(x1[i] - x2[i], 2) 
    result = math.sqrt(result) 

    return result 

Я прокомментировал приведенный выше код, показывая, где возникла проблема. Любые предложения, чтобы сделать это быстрее, приветствуются.

+0

Посмотрите [ 'np.vectorize'] (https://www.google.ru/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjJmenPv9jKAhWC1SwKHVVHCTwQFggbMAA&url=http%3A%2F%2Fdocs.scipy.org%2Fdoc%2Fnumpy-1.10. 1% 2Freference% 2Fgenerated% 2Fnumpy.vectorize.html & usg = AFQjCNGPKMc0GUdPlkR6l9Wexh7DnvUfzg & bvm = bv.113034660, d.bGg) –

+1

У вас могут быть веские причины для реализации вашего собственного классификатора (упражнение по программированию, очень специфичное, сложное, данные), но вот колодец -программированный и хорошо используемый библиотека [scikit-learn] (http://scikit-learn.org/), которая имеет множество nn алгоритмов и классификаторов. – Evert

+0

@ АнтонПротопопов: Плохой ход. Как говорится в документации: «Функция векторизации предоставляется в первую очередь для удобства, а не для производительности. Реализация по существу является циклом for». Это быстрое и грязное решение для кода, не важного для производительности. Когда вы действительно хотите преимущества скорости NumPy, 'np.vectorize' бесполезен. – user2357112

ответ

2

Похоже, вы просто хотите евклидово расстояние/2norm, которые вы можете получить через NumPy (импортируемого в np) весьма эффективно:

def euclidean_dist2(x1, x2): 
    assert(len(x1) == len(x2)) 

    x1 = np.array(x1) 
    x2 = np.array(x2) 

    norm = np.linalg.norm(x1-x2) 

    return norm 

print euclidean_dist2([1,2],[4,7]) 

который даст вам 5.83095189485, так же, как функции, которую вы имели, но векторизовано

разбив его, вы просто принимая поэлементно разницу, умножив результирующий вектор сам по себе (в квадрате ее), суммируя, то укоренение суммы:

def euclidean_dist3(x1, x2): 
    assert(len(x1) == len(x2)) 

    x1 = np.array(x1) 
    x2 = np.array(x2) 

    diff = x1 - x2 

    squared = np.transpose(diff) * diff 

    summed = sum(squared) 

    norm = np.sqrt(summed) 

    return norm 

Другими словами, вы просто принимать скалярное произведение вектора разности с собой:

def euclidean_dist4(x1, x2): 
    assert(len(x1) == len(x2)) 

    x1 = np.array(x1) 
    x2 = np.array(x2) 

    diff = x1 - x2 

    dot = np.dot(diff, diff) 

    norm = np.sqrt(dot) 

    return norm 

Различные способы достичь того же

Смежные вопросы