Как рассчитать центроид координат x, y в python

У меня есть много координат x, y, которые я сгруппировал на основе расстояния между ними. Теперь я хотел бы рассчитать центроидную меру для каждого кластера координат x, y. Есть ли способ сделать это?

Мои координаты в формате:

    coordinates_cluster = [[x1,x2,x3,...],[y1,y2,y3,...]]

Каждый кластер имеет минимальную длину в три точки, и все точки могут иметь как отрицательные, так и положительные значения x и y. Я надеюсь, что кто-то может мне помочь.

Лучший, Мартин

(Я использую Python 2.7 с Canopy 1.1.1 (32-разрядная версия) в системе Windows 7.)


person Martin Petri Bagger    schedule 30.10.2013    source источник
comment
Проблема в том, что я не знаю, с чего начать... :-(   -  person Martin Petri Bagger    schedule 30.10.2013
comment
Много ли вы знаете о вычислении центроидов? (Я не знаю, поэтому я бы начал здесь en.wikipedia.org/wiki/Centroid )   -  person Josh    schedule 30.10.2013
comment
Спасибо, я это понял :-)   -  person Martin Petri Bagger    schedule 30.10.2013
comment
Возможный дубликат Как рассчитать центроид в python   -  person sancho.s ReinstateMonicaCellio    schedule 07.09.2016


Ответы (3)


Я понял, что это не так сложно, но вот код для вычисления центроидов координат x,y:

    >>> c = [[1,4,-5],[3,-2,9]] # of the form [[x1,x2,x3],[y1,y2,y3]]
    >>> centroide = (sum(c[0])/len(c[0]),sum(c[1])/len(c[1]))

    >>> centroide
    (0, 3)
person Martin Petri Bagger    schedule 30.10.2013
comment
Вы в порядке с целыми результатами вместо более точного десятичного числа или числа с плавающей запятой? Ваш центроид y равен 10/3 или 3,33333, а не 3 точно. - person hankd; 30.10.2013

Если вас интересует вычисление центроида, как это определено в геометрии или обработке сигналов, [1, 2]:

import numpy as np
# a line from 0,0 to 1,1
x = np.linspace(0, 1, 100)
y = np.linspace(0, 1, 100)
cx = np.dot(x, y) / np.sum(y)

0.67003367003367

введите здесь описание изображения

person Reveille    schedule 13.05.2019

Принятый здесь ответ ИМХО не применяется к типичным случаям использования в реальной жизни, когда вы хотите вычислить центр тяжести формы, определяемой набором (x, y) вершин (также известных как многоугольник). Поэтому, пожалуйста, извините меня за ответ на вопрос, который был задан почти 8 лет назад, но он все еще вышел на первое место в моем поиске SO, поэтому он может подойти и другим. Я не говорю, что принятый ответ неверен в конкретном случае вопроса, но я думаю, что большинство людей, которые находят эту тему, на самом деле ищут центроид в соответствии с другим определением.

Центроид не определяется как среднее арифметическое вершин.

...что противоречит общепринятому мнению. Мы должны признать, что обычно под центроидом мы подразумеваем «среднее арифметическое положение всех точек на фигуре». Неформально это точка, в которой вырез формы может быть идеально сбалансирован на кончике булавки» (цитируя Википедию, которая цитирует здесь актуальную литературу). Обратите внимание, что это ВСЕ точки на рисунке, а не только среднее значение координат вершин. И именно здесь вы ошибетесь, если примете большинство ответов SO, которые подразумевают, что центроид является средним арифметическим координат x и y вершин, и примените это к реальным данным, которые вы могли бы собрать, выполнив эксперимент .
Плотность точек, описывающих вашу фигуру, может варьироваться вдоль линии вашей фигуры. Это лишь одно из многих возможных ограничений указанного метода. Тогда простое среднее значение координат, безусловно, не то, что вам нужно. Я проиллюстрирую это примером.

Пример

Пример многоугольника
Здесь мы видим многоугольник, состоящий из 8 вершин. Наша интуиция правильно подсказывает нам, что мы могли бы сбалансировать эту форму на кончике булавки в точке (x,y)=(0,0), сделав центроид (0,0). Но в области вокруг (-1,1) плотность точек/вершин, которые нам дали для описания этого многоугольника, выше, чем в других областях вдоль линии. Теперь, если мы вычислим центроид, взяв среднее значение вершин, результат будет смещен в сторону области с высокой плотностью.
Точка «центроид поли» соответствует истинному центроиду. Эта точка была рассчитана путем реализации описанного здесь алгоритма: https://en.wikipedia.org/wiki/Centroid#Of_a_polygon (единственное отличие: возвращает абсолютное значение площади)
Применяется к фигурам, описываемым координатами x и y N вершин типа X = x_0, x_1, …, x_(N -1), то же самое для Y. Эта фигура может быть любым многоугольником, если он не является самопересекающимся, а вершины даны в порядке появления.
Это можно использовать для вычисления, например. «настоящий» центроид контурной линии matplotlib.

Код

Вот код для приведенного выше примера и реализация указанного алгоритма:

import matplotlib.pyplot as plt

def centroid_poly(X, Y):
    """https://en.wikipedia.org/wiki/Centroid#Of_a_polygon"""
    N = len(X)
    # minimal sanity check
    if not (N == len(Y)): raise ValueError('X and Y must be same length.')
    elif N < 3: raise ValueError('At least 3 vertices must be passed.')
    sum_A, sum_Cx, sum_Cy = 0, 0, 0
    last_iteration = N-1
    # from 0 to N-1
    for i in range(N):
        if i != last_iteration:
            shoelace = X[i]*Y[i+1] - X[i+1]*Y[i]
            sum_A  += shoelace
            sum_Cx += (X[i] + X[i+1]) * shoelace
            sum_Cy += (Y[i] + Y[i+1]) * shoelace
        else:
            # N-1 case (last iteration): substitute i+1 -> 0
            shoelace = X[i]*Y[0] - X[0]*Y[i]
            sum_A  += shoelace
            sum_Cx += (X[i] + X[0]) * shoelace
            sum_Cy += (Y[i] + Y[0]) * shoelace
    A  = 0.5 * sum_A
    factor = 1 / (6*A)
    Cx = factor * sum_Cx
    Cy = factor * sum_Cy
    # returning abs of A is the only difference to
    # the algo from above link
    return Cx, Cy, abs(A)

# ********** example ***********
X = [-1, -0.8,  -0.6,  1,   2,  1, -1,   -2]
Y = [ 1,    1,     1,  1, 0.5, -1, -1, -0.5]

Cx, Cy, A = centroid_poly(X, Y)

# calculating centroid as shown by the accepted answer
Cx_accepted = sum(X)/len(X)
Cy_accepted = sum(Y)/len(Y)

fig, ax = plt.subplots()
ax.scatter(X, Y, label='vertices')
ax.scatter(Cx_accepted, Cy_accepted, label="mean of vertices")
ax.scatter(Cx, Cy, label='centroid poly')

# just so the line plot connects xy_(N-1) and xy_0
X.append(X[0]), Y.append(Y[0])
ax.plot(X, Y, label='polygon')

ax.legend(bbox_to_anchor=(1, 1))
ax.grid(), ax.set_aspect('equal')
person XIII_    schedule 25.06.2021