• Регистрация
Хасбулат Нурмагомедов
Хасбулат Нурмагомедов +43.63
н/д

Строим графики в MATLAB 3 (гистограммы)

17.12.2020

Долго не хотел браться за этот вопрос, но все же бесконечно от него уходить не получится. При всей кажущейся простоте вопрос построения гистограмм весьма обширен. Есть такая книжка Handbook of statistics. Так вот, в ней только методов разбиения на интервалы с десяток. Я постараюсь в эти вопросы не влезать и показать основные, которые есть в MATLAB.

Кроме того, попробую описать в двух словах, на пальцах, что такое гистограмма. Думаю, в рамках обзорной поверхностной статьи подобное объяснение уместно. Допустим, мы сделали сто измерений чего-либо, и, кроме того, мы знаем, что должно быть на выходе – некий эталон, пусть его значение равно 10см, но все наши изменения немного от него отличаются (мерим мы прибором с точностью 0.01см). Измерения готовы, теперь нам интересно сколько измерений лежат в диапазоне [0:0.1), [0.1:0.2), [0.2:0.3], (0:-0.1], (-0.1:-0.2], (-0.2:-0.3], считаем и записываем результат в виде вектора. Теперь мы получили вектор интервалов и вектор количества значений, которые в эти интервалы попадают. Графическое отображение зависимости одного от другого и есть гистограмма.

Сколько интервалов, их границы и т.д. и есть те самые методы, про которые я говорил в первом абзаце, логарифмический, Стерджеса и т.д. и т.п.

Итак, давайте слету построим какую-нибудь гистограмму.

x = randn(1000, 1);
h = histogram(x)

Ну вот, у нас и получилась какая-то гистограмма. Давайте разбираться…

Во-первых, обратите внимание на отсутствие точки с запятой в конце второй строки. Помимо всего прочего MATLAB создает системный объект h. Раз уж мы заговорили про объект и не поставили точку с запятой, то посмотрим в консоль, там распечатается следующее:

h = 

  Histogram with properties:

             Data: [1000×1 double]
           Values: [1 0 3 3 6 21 34 39 66 87 104 117 129 113 90 63 48 27 28 10 7 3 0 1]
          NumBins: 24
         BinEdges: [1×25 double]
         BinWidth: 0.3000
        BinLimits: [-3.6000 3.6000]
    Normalization: 'count'
        FaceColor: 'auto'
        EdgeColor: [0 0 0]

  Show all properties

Заодно построим график случайной величины, гистограмму которой мы построили.

plot(x);

Попробуем подвести промежуточный итог. Мы получили системный объект h, который был построен с использованием автоматического разбиения на интервалы и начальными настройками отображения. Далее есть два пути. Первый – изменять параметры нашего системного объекта, второй ­­– задать параметры на стадии его создания. Ну и все вместе тоже можно, естественно.

x = randn(10000, 1);
h = histogram(x); % Добавил точку с запятой
h.NumBins = 2; % Сократим количество интервалов до двух

Выполнив код, приведенный выше, я вижу не совсем то, что ожидал:

Раз уж у меня распределение с нулевым матожиданием, то я наивно полагал, что автоматический алгоритм поставит мне два бина с границей в нуле. Не верим мне на слово, проверяем:

x = randn(10000, 1);
E = ones(1,10000);
E = 1/length(x) * E * x

%Вывод в консоли
>> E =

   -0.0053

Ну ладно, я ему помогу:

x = randn(10000, 1);
h = histogram(x); % Добавил точку с запятой
h.NumBins = 2;
h.BinEdges = -10:10:10;

Другое дело! Отмечу, что гистограммы я использую довольно редко. Думаю, пальцев хватит, чтобы пересчитать, сколько раз я вызывал эту функцию до написания этой статьи. Поэтому в режиме экспериментов для меня проще сначала создать объект, а потом играть с параметрами из списка. Однако если код потребуется финализировать, то разумнее будет создать сразу требуемый объект, так что для общности рассуждений приведем второй вариант записи:

x = randn(10000, 1);
edges = [-10,-2:0.1:2,10]; 
h = histogram(x, edges);

Дабы не тянуть кота за хвост, я добавил еще одну опцию в этот пример, а именно возможность задавать интервалы разной ширины.

Теперь пару слов про категорийные гистограммы

% Задаем массив значений
A = [1 1 0 0 1 1 0 0 NaN 0 1 0 0 1 1 0 NaN];
 
% Разбиваем его на категории
C = categorical(A,[0 1 NaN], {'Yes', 'No', 'Undeclared'});

% Строим гистограмму распределения по категориям 
histogram(C, 'Barwidth', 0.5);

Допустим, мы проверили опрос и API сервера вернула нам результат из нулей единиц и NaN, делим их на категории:да, нет, не определился - и строим столбцы, соответствующие каждой из них. Вроде бы все просто. Про веб-сервер ThingSpeak может быть поговорим чуть позже, если я разживусь лицензией.

 

Теперь еще важный момент: нормализация. Допустим, я хочу построить плотность распределения вероятностей нашей случайной величины. Чтобы наша гистограмма таковой стала, надо чтобы сумма всех столбцов была равна единице, но это опять же на пальцах… ну да и ладно, строим:

x = randn(1000,1);
h = histogram(x,'Normalization','probability');

% Первая гистограмма
x = randn(1000,1);
h = histogram(x,'Normalization','probability');
 
% Вторая гистограмма смещенного распределения
x_1 = randn(1000,1) + 1;
hold on;
h1 = histogram(x_1,'Normalization','probability');

Ну и напоследок немного об украшательствах, тут все очень просто. В принципе, точно также, как в предыдущих статьях. Пойдем по первому пути, о котором я говорил выше: открываем системный объект и копаемся в настройках, находим параметры, которые могут отвечать за внешний вид гистограммы и меняем их:

% первая гистограмма
x = randn(1000,1);
h = histogram(x,'Normalization','probability');
 
%Меняем внешний вид
h.FaceColor = [0 0.5 0.5];
h.EdgeColor = 'r';
 
% Вторая гистограмма смещенного распределения
x_1 = randn(1000,1) + 1;
hold on;
h1 = histogram(x_1,'Normalization','probability');

Про подписи осей, заголовки и т.д. читаем в предыдущих статьях. Надеюсь, был полезен, удачи и до скорых встреч!

Теги

      17.12.2020

      Комментарии