Как использовать sum () / average () для namedtuple в python? - PullRequest
1 голос
/ 28 марта 2019
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
points = [Point(x=1.0, y=1.0), Point(x=2.0, y=2.0)] 

Я бы хотел вычислить среднюю точку из списка points, то есть получить Point(1.5, 1.5) в результате:

point = average(points) # x = 1.5, y = 1.5

например. Я знаю, что есть np.average(points, axis=0), если points.shape равно (N, 2), но вместо этого я бы предпочел оставить именованный кортеж.

Ответы [ 4 ]

2 голосов
/ 28 марта 2019

Рассчитать среднее значение по координатам:

import numpy as np
Point(np.average([p.x for p in points]),
      np.average([p.y for p in points]))
#Point(x=1.5, y=1.5)

Или, лучше, неявно преобразовать список точек в массив значений, получить среднее значение и преобразовать результат обратно в точку

Point(*np.average(points, axis=0))
#Point(x=1.5, y=1.5)
1 голос
/ 28 марта 2019

Может быть, я что-то упускаю, но если вы хотите избежать numpy, тогда вы можете сделать

>>> Point(sum(p.x for p in points)/len(points),sum(p.y for p in points)/len(points))
Point(x=1.5, y=1.5)

Хотя, кажется, немного окольным.

0 голосов
/ 28 марта 2019

Вот простой способ, использующий только встроенные Python:

In [1]: from collections import namedtuple
   ...: Point = namedtuple('Point', ['x', 'y'])
   ...: points = [Point(x=1.0, y=1.0), Point(x=2.0, y=2.0)]
   ...:

In [2]: import statistics

In [3]: Point(*map(statistics.mean, zip(*points)))
Out[3]: Point(x=1.5, y=1.5)

Почему вы используете numpy для начала?Здесь нет особого смысла.

0 голосов
/ 28 марта 2019

Это новый подкласс namedtuple, который имеет classmethod для построения новой точки из среднего значения или суммы последовательности точек.

from collections import namedtuple


class Point(namedtuple('Point', ['x', 'y'])):
    @classmethod
    def from_average(cls, points):
        from_sum = cls.from_sum(points)

        return cls(from_sum.x / len(points), from_sum.y / len(points))

    @classmethod
    def from_sum(cls, points):
        if not all(isinstance(p, cls) for p in points):
            raise ValueError('All items in sequence must be of type {}'.format(cls.__name__))

        x = sum(p.x for p in points)
        y = sum(p.y for p in points)

        return cls(x, y)


point_1 = Point(1.0, 1.0)
point_2 = Point(2.0, 2.0)

point_3 = Point.from_average([point_1, point_2])

point_3
# Point(x=1.5, y=1.5)

point_4 = Point.from_sum([point_1, point_2])

point_4
# Point(x=3.0, y=3.0)
...