Сбит с толку numpy.unique()

avatar
Maggie
9 августа 2021 в 05:01
203
2
2

В качестве расширения моего предыдущего проекта, где уравнение X[i+1]=R*X[i](1-X[i]) используется для демонстрации хаотической системы (в зависимости от R). Теперь я пытаюсь построить бифуркационный граф.

Что касается кода, я определил функцию для выполнения фактических вычислений и извлечения последних 100 вычисленных значений (для обеспечения достижения равновесия), чтобы построить разветвленную зависимость R от x[i], я добавляю каждое значение R в пустой список X-данных и несколько (то есть возвращаемые 100 значений) x[i] в ​​список Y-данных (так что на самом деле это вложенный список...)

Дело в том, что в зависимости от значения R x[i] может быть либо одним значением (после достижения равновесия), либо несколькими значениями. Поэтому я подумал «очистить» вложенный список Y-данных с помощью numpy.unique(), чтобы удалить все реплицированные значения.

Странно, но когда я не делаю дополнительный шаг "очистки", код действительно работает.

Но когда я ввожу x = np.unique(logistic_calc(R,N)), мне выдает ошибку ValueError: setting an array element with a sequence.

Ниже приведен работающий код...

import numpy as np
import matplotlib.pyplot as plt

R = 0.2
N = 10_000
x0 = 0.5

def logistic_calc(R,N):
    x = np.empty(N)
    x[0] = x0
    for i in range(1, N):
        x[i] = R* x[i-1] * (1 - x[i-1])
    return x[-100:]

x_lst = [] 
y_lst = []
for r in np.linspace(0.1,4,100):
    R = r 
    x = logistic_calc(R,N)
    x_lst.append(r)
    y_lst.append(x)

plt.figure(figsize=(7, 4))
plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")
plt.ylim(0, 1)
plt.grid(c="lightgray")
plt.xlabel(r"$r$")
plt.ylabel(r"$x_n$")

plt.show()
Источник

Ответы (2)

avatar
nonin
9 августа 2021 в 07:40
1

Из документации matplotlib, параграф "Отображение нескольких наборов данных":

"Если x и/или y являются двумерными массивами, для каждого столбца будет отображаться отдельный набор данных. Если оба x и y являются двумерными, они должны иметь одинаковую форму. Если только один из них является двумерным с формой (N , m) другой должен иметь длину N и будет использоваться для каждого набора данных m."

Не указано явно, что все подсписки должны иметь одинаковую длину. Но это относится только к двумерным массивам, а не к рваным вложенным последовательностям. Чтобы понять поведение plt.plot, просто представьте, что x и y будут преобразованы в массивы numpy. Во втором случае, поскольку y_lst содержит списки разной длины, это преобразование невозможно.

Я бы выбрал что-то вроде этого:

plt.figure(figize=(7, 4))
for r in np.linspace(1, 4, 100):
    x = np.unique(logistic_calc(r, N))
    plt.plot([r], [x], '.', ms=.5, c="royalblue")  # a little bit tricky!
    # OR
    # plt.plot([r] * len(x), x, '.', ms=.5, c="royalblue")

...
plt.show()
    
Maggie
9 августа 2021 в 08:01
0

Привет спасибо за быстрый ответ. Теперь я примерно понимаю проблему. По сути, plt.plot отрисовывает несколько наборов, когда либо x-данные, либо y-данные имеют более 1 измерения, поэтому проблема сопоставления размеров требует внимания. Тогда мне интересно, когда несколько y-данных соответствуют одному x-данным, может ли plt.scatter быть решением? Или это в основном следует той же идее, что и plt.plot ...?

nonin
9 августа 2021 в 08:33
1

Например, plt.plot(x=[0, 1, 2, 3], y=[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] будет работать с len(x) == len(y) и означает создание следующих 3 графиков plt.plot([0, 1, 2, 3], [1, 4, 7, 10]), plt.plot([0, 1, 2, 3], [2, 5, 8, 11]) и plt.plot([0, 1, 2, 3], [3, 6, 9, 12]). Вот почему все подсписки должны иметь одинаковое количество элементов. Таким образом, в первом случае, когда x_lst представляет собой простой список длины nR, а y_lst содержит nR списки длины m, plt.plot(x_lst, y_lst) следует рассматривать как ""Нарисуй меня горизонтально"" m> строк (x_lst, y_lst[i])".

nonin
9 августа 2021 в 08:38
1

И plt.scatter строго требует, чтобы x и y были одного размера. Обратите внимание, что plt.scatter обрабатывает каждую точку как отдельный объект, а plt.plot с аргументом o обрабатывает их как одну линию. Следовательно, если вы хотите, чтобы все точки имели одинаковый вид, всегда используйте plt.plot.

avatar
Ian Graham
9 августа 2021 в 05:23
1

Когда я запускаю ваш пример с np.unique, я получаю ...

...

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")

... more stack trace

ValueError: setting an array element with a sequence.

Таким образом, ошибка явно происходит в строке ...

plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")

так как формы x_lst и y_lst больше не совпадают при использовании np.unique.

Вы можете заставить код работать, перебирая каждый индекс x_lst и y_lst и рисуя их отдельно...

import numpy as np
import matplotlib.pyplot as plt

R = 0.2
N = 10_000
x0 = 0.5

def logistic_calc(R,N):
    x = np.empty(N)
    x[0] = x0
    for i in range(1, N):
        x[i] = R* x[i-1] * (1 - x[i-1])
    return x[-100:]

x_lst = [] 
y_lst = []
for r in np.linspace(0.1,4,100):
    R = r 
    x = logistic_calc(R,N)
    x = x.reshape(100)
    x_lst.append(r)
    y_lst.append(np.unique(x.round(decimals=4)))

plt.figure(figsize=(7, 4))
for x, y in zip(x_lst, y_lst):
    plt.plot([x]*len(y), y, ls='', marker='.',ms='0.5', c="royalblue")
plt.ylim(0, 1)
plt.grid(c="lightgray")
plt.xlabel(r"$r$")
plt.ylabel(r"$x_n$")

plt.show()
Maggie
9 августа 2021 в 06:03
1

Привет, спасибо за модификацию кода. Моя путаница заключалась в том, что до использования np.unique(x) в конце концов после добавления цикла for r in np.linspace(0.1,4,100) y_lst представляет собой список из 100 элементов, где каждый элемент представляет собой список, состоящий из 100 чисел с плавающей запятой, а x_lst - это просто список из 100 чисел с плавающей запятой, и ниже в этой ситуации plt.plot(x_lst, y_lst) работает нормально. Но почему, когда я «очищаю» y_lst (все еще список из 100 элементов, но каждый элемент может быть списком, состоящим из одного или нескольких чисел с плавающей запятой), а затем plt.plot не работает?

Ian Graham
9 августа 2021 в 12:14
0

Это состояние nonin, хотя вы передаете ему списки одинаковой длины, plt.plot ожидает, что каждый список можно преобразовать в простой np.ndarray. Ваш список y является неоднородным, поэтому его нельзя преобразовать в одномерный или двумерный ndarray примитивных числовых типов (int, float и т. д.). В лучшем случае вы можете создать тип ndarray типа object из y, но здесь это не сработает.

Maggie
9 августа 2021 в 12:54
0

Я понимаю! Спасибо за помощь!