#python #numpy
#python #numpy
Вопрос:
У меня есть список длиной 50, заполненный массивами длиной 5. Я пытаюсь вычислить расстояние между каждым массивом в списке и обновить массив numpy значениями.
Вычисление расстояния просто извлекает квадратный корень из суммы квадратов расстояния между каждым элементом в массивах.
Когда я пытаюсь:
primaryCustomer = np.zeros(shape = (50,50))
for customer in range(0,50):
for pair in range(0,50):
thisCustomer = [0 for i in range(51)]
if customer == pair:
thisCustomer[pair] = 999
else:
calculateScores = (((Customer[customer][0]-Customer[pair][0])**2
(Customer[customer][1]-Customer[pair][1])**2
(Customer[customer][2]-Customer[pair][2])**2
(Customer[customer][3]-Customer[pair][3])**2
(Customer[customer][4]-Customer[pair][4])**2 )**(0.5))
thisCustomer[pair] = calculateScores
np.append(primaryCustomer, thisCustomer)
происходит пара вещей:
- Последняя итерация этого пользователя возвращает список всех нулей, за исключением последнего элемента 999 (соответствующего части ‘if’ инструкции выше). Итак, я знаю, что он может обновить список, но он не делает этого в части ‘else’.
- Я хочу, чтобы массив ‘primaryCustomer’ обновлялся с указанием клиента в качестве индекса и всех вычисленных значений с каждой парой в качестве значений строк, но, похоже, он вообще не обновляется
Любые изменения, которые я делаю, например, пытаясь обрабатывать этого пользователя в цикле как массив вместо списка и добавлять к нему, в конечном итоге исправляют одну область, но еще хуже портят другие.
Вот как я получаю данные клиента:
Customer = [[0,0,0,0,0] for i in range(51)]
for n in range(51):
Customer[n] = np.ones(5)
Customer[n][randint(2,4):5] = 0
np.random.shuffle(Customer[n])
Я знаю, что могут быть пакетные способы сделать это, но я пытаюсь понять, как такие вещи, как KNN, работают в фоновом режиме, поэтому я хотел бы продолжить выяснять логику в циклах, подобных описанному выше. Помимо этого, любая помощь была бы высоко оценена.
Комментарии:
1. Это не то, как вы используете
np.append
. Прочитайте документы, а затем держитесь подальше от этой плохо названной функции. Вы уже выделили место для этих значений в массиве. Назначьте им обычную индексацию массива. Вы показываете, что уже знаете, как присваивать значения элементу списка.2. @datahappy: Если я правильно понимаю ваш пост, вам не нужно эффективное (numpy-ish) решение. Вы просто хотите придерживаться своих циклов и просто исправить их, чтобы заставить их работать. Правильно ли это понимание?
3. @fountainhead Я так думаю. По крайней мере, я так это читаю
Ответ №1:
Я думаю, что это то, к чему вы стремитесь, но поправьте меня, если я ошибаюсь:
import numpy as np
from random import randint
Customer = [[0, 0, 0, 0, 0] for i in range(51)]
for n in range(51):
Customer[n] = np.ones(5)
Customer[n][randint(2, 4):5] = 0
np.random.shuffle(Customer[n])
primaryCustomer = np.zeros(shape=(50, 50))
for customer in range(0, 50):
thisCustomer = [0 for i in range(51)]
for pair in range(0, 50):
if customer == pair:
primaryCustomer[customer][pair] = 999
else:
calculateScores = (((Customer[customer][0] - Customer[pair][0]) ** 2
(Customer[customer][1] - Customer[pair][1]) ** 2
(Customer[customer][2] - Customer[pair][2]) ** 2
(Customer[customer][3] - Customer[pair][3]) ** 2
(Customer[customer][4] - Customer[pair][4]) ** 2) ** 0.5)
primaryCustomer[customer][pair] = calculateScores
print(primaryCustomer)
Я думаю, что основной проблемой, которую я обнаружил в ваших циклах, было расположение thisCustomer = [0 for i in range(51)]
, я думаю, вы хотели поднять его еще на один уровень, как в моем. Я не вижу никакой необходимости в этой строке, хотя и изменил ее thisCustomer[pair]
для прямой записи в primaryCustomer[customer][pair]
вместо этого, тем самым сводя на нет необходимость в thisCustomer = [0 for i in range(51)]
каждом цикле, что ускорило бы вашу программу и улучшило использование памяти за счет полного удаления строки.
Пример вывода:
[[999. 2.23606798 1. … 2. 0.
1.73205081]
[ 2.23606798 999. 2. … 1. 2.23606798
1.41421356]
[ 1. 2. 999. … 1.73205081 1.
2. ]
…
[ 2. 1. 1.73205081 … 999. 2.
1.73205081]
[ 0. 2.23606798 1. … 2. 999.
1.73205081]
[ 1.73205081 1.41421356 2. … 1.73205081 1.73205081
999. ]]
Комментарии:
1.
primaryCustomer[customer, pair] = calculateScores
является более идиоматичным.2. @hpaulj Спасибо за это! Я оставлю это на усмотрение OP, какую реализацию он / она выберет, чтобы быть более читаемой. Обычно я предпочитаю двойную индексацию, как в моем посте, потому что я могу визуализировать одну как строку, а другую как столбец, но это отличный трюк, который нужно знать.
3. Двойная индексация отлично работает при использовании скалярных индексов. Первый индекс выбирает строку, второй выбирает элемент из этой строки. Но это не сработает, если вы используете фрагменты или списки, которые возвращали бы несколько строк.
4. @hpaulj Итак, вы говорите, что можете использовать нотацию среза с помощью вашего метода? Что-то вроде
primaryCustomer[[0:customer], [0:pair]] = someArray
и вы не можете переписать это вprimaryCustomer[0:customer][0:pair] = someArray
?5. Спасибо. Это было очень полезно
Ответ №2:
Пара вещей, на которые следует обратить внимание в первую очередь.
primaryCustomer[a][b] = primaryCustomer[b][a]
потому что вы используете метрику расстояния. Это означает, что диапазоны в ваших двух циклах for могут быть сброшены:
numCustomers = 51
primaryCustomer = np.zeros(shape = (numCustomers, numCustomers))
for customerA in range(numCustomers-1):
for customerB in range(customerA 1, numCustomers):
primaryCustomer[customerA][customerB] = dist(customerA,customerB)
primaryCustomer = np.transpose(primaryCustomer)
Примечание * вы можете изменить диапазон второго цикла for, чтобы он также начинался с 0, чтобы сохранить исходную структуру цикла, но тогда вам нужно будет удалить строку переноса. Вы также можете иметь
primaryCustomer[a][b] = primaryCustomer[b][a] = dist(a,b)
если вы предпочитаете не использовать транспонирование, но все же избегаете ненужных вычислений.
primaryCustomer = np.zeros(shape = (50,50))
Я предполагаю, что он предназначен для хранения расстояния между двумя клиентами. Однако, похоже, у вас 51 клиент, а не 50?- Вам следует подумать о вычислении расстояний более общим способом. т. Е. Как вы могли бы заставить вычисление расстояния работать независимо от размера списка?
- Почему вы создаете начальный 2D-массив из 0 для хранения расстояния, а затем добавляете к нему? Создание
thisCustomer
списка не кажется необходимым, и фактически решение, опубликованное Reedinationer, инициализирует его, но даже никогда не использует. Кроме того, как кто-то уже заявил, это не такnp.append
работает. Вам лучше всего изменить матрицу расстояний, которую вы создали изначально, напрямую. - Почему
primaryCustomer[a][a] = 999
? Разве расстояние между списком и самим собой не должно быть равно 0? Если вы действительно хотите, чтобы это было 999, я рекомендую вам выяснить, как изменить приведенный выше блок кода, чтобы учесть это.