Страницы

Поиск по вопросам

суббота, 15 июня 2019 г.

Работа с несколькими массивами в Python

Есть массивы с точками:
X[0.0, 0.0, 0.0, 0.0],Y[0.0, 0.3333, 0.6667, 1.0], kX[0.0, 0.0, 0.0],kY[0.1667, 0.5, 0.8333]
Нужно сформировать двумерные массивы R2, U и V размера(3,4), элементы которых считаются по формулам:
r2 = math.sqrt(math.pow((kX[k]-X[i]), 2) + math.pow((kY[k]-Y[i] ) , 2)) u = 1 / (2 * math.pi) * ((kY[k]-Y[i]) / math.pow(r2[k][i], 2)) v = - 1 / (2 * math.pi) * ((kX[k]-X[i]) / math.pow(r2[k][i], 2))
Поскольку я новичек, меня особенно интересует подробное описание следующего кода
###псевдокод#### r2 = math.sqrt(math.pow((kX[k]-X[i]), 2) + math.pow((kY[k]-Y[i] ) , 2)) ### реализация на питоне #### r2 = [[(cp.y - p.y)**2 + (cp.x - p.x)**2 for p in points] for cp in control_points]
где используется collections.namedtuple и вообще как обращаться к элементам массивов без использования циклов, желательно на этом примере.
Случай с точками двух массивов понятен:
u = [[1 / (2 * math.pi)*(kx - x) for x in X] for kx in kX] v = [[1 / (2 * math.pi)*(ky - y) for y in Y] for ky in kY]
А как быть, если нужно:
u = [[1 / (2 * math.pi)*(kx - x) for x in X] for kx in kX] / r2[k][i] v = [[1 / (2 * math.pi)*(ky - y) for y in Y] for ky in kY] / r2[k][i]


Ответ

Если вы хотите использовать X, Y, kX, kY как Python-списки напрямую:
import math
r2 = [[((kx - x)**2 + (ky - y)**2)**.5 for x, y in zip(X, Y)] for kx, ky in zip(kX, kY)] u = [[(kx - x) / (2 * math.pi * r2ki) for x, r2ki in zip(X, r2k)] for kx, r2k in zip(kX, r2)] v = [[(ky - y) / (2 * math.pi * r2ki) for y, r2ki in zip(Y, r2k)] for ky, r2k in zip(kY, r2)]
zip() это встроенная в Питон функция:
>>> list(zip(range(3), "abc")) [(0, 'a'), (1, 'b'), (2, 'c')]
Происхождение названия от zipper—застёжка-молния: zip() "сшивает" переданные аргументы.
Point2D (collections.namedtuple)
Если:
points = list(map(Point2D, X, Y)) control_points = list(map(Point2D, kX, kY))
тогда код для r2 идентичен уже приведённому решению (c точностью до вызова sqrt):
r2 = [[((cp.y - p.y)**2 + (cp.x - p.x)**2)**.5 for p in points] for cp in control_points]
Пример:
>>> import collections >>> Point2D = collections.namedtuple('Point2D', 'x y') >>> X, Y = [0.0, 0.0, 0.0, 0.0], [0.0, 0.3333, 0.6667, 1.0] >>> points = list(map(Point2D, X, Y)) >>> points == [Point2D(x, y) for x, y in zip(X, Y)] True >>> points [Point2D(x=0.0, y=0.0), Point2D(x=0.0, y=0.3333), Point2D(x=0.0, y=0.6667), Point2D(x=0.0, y=1.0)] >>> [p.y for p in points] [0.0, 0.3333, 0.6667, 1.0]
numpy
Eсли работать с X, Y, kX, kY как с numpy-массивами:
>>> import numpy as np >>> X, Y, kX, kY = map(np.array, [X, Y, kX, kY]) >>> r2 = ((kX[:,None] - X[None,:])**2 + (kY[:,None] - Y[None,:])**2)**.5 >>> r2 array([[ 0.1667, 0.1666, 0.5 , 0.8333], [ 0.5 , 0.1667, 0.1667, 0.5 ], [ 0.8333, 0.5 , 0.1666, 0.1667]]) >>> u = (kX[:,None] - X[None,:]) / (2 * math.pi * r2) >>> v = (kY[:,None] - Y[None,:]) / (2 * math.pi * r2) >>> v array([[ 0.15915494, -0.15915494, -0.15915494, -0.15915494], [ 0.15915494, 0.15915494, -0.15915494, -0.15915494], [ 0.15915494, 0.15915494, 0.15915494, -0.15915494]])
Здесь индексация с None добавляет новую размерность (из одномерного массива создаёт двумерный):
>>> kY array([ 0.1667, 0.5 , 0.8333]) >>> kY[:,None] array([[ 0.1667], [ 0.5 ], [ 0.8333]])

Комментариев нет:

Отправить комментарий