проект Сервер DOS® под виртуальной машиной

Выбросы (статистика)

Сегодня речь пойдёт о таком понятии как статистические выбросы. Возможно, вы зададите вопрос: "Что это?". На него более-менее хорошо отвечает Википедия: http://ru.wikipedia.org/wiki/Выброс_(статистика). Кроме того, статистика изучается в курсе математики вуза.
В этой статье я попробую объяснить этот термин с помощью простого примера.
Допустим, какая-то специализированная организация (в России это может быть Облстат) занимается сбором статистических данных с последующим вычислением средних показателей или по стране, или по области, или по городу. В качестве примера взята городская поликлиника. Её штат состоит из администрации, специалистов, персонала среднего звена и обслуживающего персонала (уборщицы, дворники, вахтёр и так далее).
Облстат собирается расчитать среднюю зарплату в месяц в медицинском учреждении для объективной оценки роста доходов сотрудников. (Насколько эта оценка "объективна", поймём в дальнейшем.) Для проведения подобных вычислений организация запросила в поликлинике сведения о доходах сотрудников. И вот что получила (зарплаты взяты произвольно):

Должность Зарплата на человека, руб. Кол-во чел.
Заместитель главного врача по лечебной части 23000 1
Вахтёр 4500 2
Главный врач 65000 1
Секретарь 15345 1
Бухгалтер 21500 10
Главный бухгалтер 35000 1
Терапевт 17000 14
Педиатр 17437 15
Отоларинголог 16877 2
Заведующий педиатрическим отделением 18000 1
Заведующий терапевтическим отделением 18000 1
Невропатолог 22300 1
Заместитель главного врача по контрольно-экспертной комиссии 17200 1
Начальник отдела кадров 18000 1
Инспектор отдела кадров 18000 1
Программист 18200 1
Инженер-электроник 18000 1
Электрик 17300 1
Сантехник 14700 2
Дворник 4000 2


Исходя из таблицы, мы получаем массив чисел следующего содержания: 23000, 4500, 4500, 65000, 15345, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 35000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 16877, 16877, 18000, 18000, 22300, 17200, 18000, 18000, 18200, 18000, 17300, 14700, 14700, 4000, 4000.
Если брать методику расчёта средней зарплаты по среднему арифметическому числового ряда, то мы получаем следующую величину: (23000 + (4500 * 2) + 65000 + 15345 + (21500 * 10) + 35000 + (17000 * 14) + (17437 * 15) + (16877 * 2) + 18000 + 18000 + 22300 + 17200 + 18000 + 18000 + 18200 + 18000 + 17300 + (14700 * 2) + (4000 * 2)) / 60 = 1098054 / 60 = 18300.90 (рублей) - средняя зарплата в поликлинике.
Но в таблице мы выдим явные выбросы, портящие реальный вид статистики: это зарплаты в 65000 рублей, 35000 рублей, которые на фоне 17000 рублей выглядят резко выделяющимися. (На практике бывает, к примеру, что зарплата рядовых сотрудников 25000 рублей, а генерального директора - 300000 рублей. Это тоже явный выброс из статистики, который искуственно повышает средний показатель доходов в организации.)
Мы это понимаем и, очевидно, недовольны статистикой, поскольку эффекта от неё нет. Но как же объективно понять ту грань, где показатель сильно выбивается из общего ряда, а где не очень?
Для этого может хорошо подойти метод вычисления средних показателей. Заключается он в следующем. Вначале мы рассчитываем средние арифметические для ряда чисел M1...Mn, M1...M(n-1), M1...M(n-2), ..., M1...M1. Затем находим среднее арифметичесое A1 от средних арифметических. Те числа M, чьи показатели отличаются более, чем в 2 раза (то есть на 100% и выше), от показателя A1, отсеиваем на 1-ом отборе: это явные выбросы.
На 2-ом отборе уже в сформировавшемся ряде чисел также могут присутствовать выбросы (к примеру: 1, 20, 20, 20, 20, 20, 20, 21, 21; 1 - это выброс). Поэтому вычисляем, сколько раз в ряду встречается каждое число. Вслед за этим находим максимальное количество повторов maxAmount и среднее количество повторов uniqueAver. Далее оставляем только те числа N, которые N <= maxAmount, и при этом N >= (uniqueAver / 2); то есть числа, повтор которых выше среднего показателя не менее, чем в 2 раза. Редко встречающиеся числа отсеиваются.
Так мы получаем объективную статистику по показателям.
Весь алгоритм расчёта выбросов я оформил в виде функции outlier() на JavaScript, которая на вход получает исходный массив чисел и на выход выдаёт тот массив чисел, по которому можно уже смело рассчитываеть средний показатель через среднее арифметическое. Все выбросы отсеиваются. Код функции приведён ниже.

/* --- НАЧАЛО функции анализа статистического выброса --- */
/* http://ru.wikipedia.org/wiki/Выброс_(статистика) */
/* автор: Ефремов А. В. (a.k.a. "Nikodim") */
function outlier(nr) {
   var average = new Array(), z = 0, aver = 0, nr02 = new Array(), nr03 = new Array(), c = 0;
   var uniqueNr = new Array(), uniqueAmount = new Array(), uniqueAver = 0, maxAmount = 0;
   var nrRes = new Array(), nrQty = new Array();

/* упорядочиваем массив */
   for (var x = 0; x < nr.length - 1; x++) {
      for (var y = x + 1; y < nr.length; y++) {
         if (nr[x] > nr[y]) {
            z = nr[x];
            nr[x] = nr[y];
            nr[y] = z;
         }
      }
   }

/* ищем средние арифметические */
   for (x = 0; x < nr.length; x++) {
      z = 0;
      for (y = 0; y <= x; y++) {
         z += nr[y];
      }
      average[average.length++] = z / (x + 1);
   }

/* ищем среднее арифметическое от средних арифметических */
   for (x = 0; x < average.length; x++) {
      aver += average[x];
   }
   aver = aver / average.length;

/* числа, которые попадут в 1-й отбор */
   for (x = 0; x < nr.length; x++) {
      if (Math.abs(nr[x]) <= Math.abs(2 * aver)) { /* если значение числа не превышает двукартного показателя ср. арифм. */
         nr02[nr02.length++] = nr[x];
      }
   }

/* среднее арифметическое по числам 1-го отбора */
   z = 0;
   aver = 0;
   for (x = 0; x < nr02.length; x++) {
      aver += nr02[x];
   }
   aver = aver / nr02.length;


   z = nr02[0]; c = 1;
   for (x = 1; x < nr02.length; x++) {
      if (nr02[x] == z) {
         c++;
      } else {
         uniqueNr[uniqueNr.length++] = z; uniqueAmount[uniqueAmount.length++] = c;
         z = nr02[x];
         c = 1;
      }
   }
   uniqueNr[uniqueNr.length++] = z; uniqueAmount[uniqueAmount.length++] = c;

   maxAmount = 0;
   for (x = 0; x < uniqueAmount.length; x++) {
      uniqueAver += uniqueAmount[x];
      if (maxAmount < uniqueAmount[x]) {
         maxAmount = uniqueAmount[x];
      }
   }
   uniqueAver = Math.round(Math.round(100 * uniqueAver / uniqueAmount.length) / 100);

   for (x = 0; x < uniqueAmount.length; x++) {
      if ((uniqueAmount[x] <= maxAmount) && (uniqueAmount[x] >= Math.floor(uniqueAver / 2))) {
         nrRes[nrRes.length++] = uniqueNr[x];
         nrQty[nrQty.length++] = uniqueAmount[x];
      }
   }


/* числа, которые попадут во 2-й отбор */
   for (x = 0; x < nrRes.length; x++) {
      for (y = 0; y < nrQty[x]; y++) {
         nr03[nr03.length++] = nrRes[x];
      }
   }

/* если во 2-ом отборе ничего не найдено, берутся все числа из 1-го отбора */
   if (nr03.length < 1) {
      for (x = 0; x < uniqueNr.length; x++) {
         for (y = 0; y < uniqueAmount[x]; y++) {
            nr03[nr03.length++] = uniqueNr[x];
         }
      }
   }


   return (nr03);
}
/* --- КОНЕЦ функции анализа статистического выброса --- */

Применительно к нашему примеру, вызовим эту фунцию на обработку и рассчитаем средний показатель зарплат без учёта, так называемых, выбросов.

/* ИСХОДНЫЕ ДАННЫЕ ЗДЕСЬ!!!!!! */
var nr = new Array(23000, 4500, 4500, 65000, 15345,
21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500,
21500, 21500, 35000, 17000, 17000, 17000, 17000, 17000,
17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000,
17000, 17437, 17437, 17437, 17437, 17437, 17437, 17437,
17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437,
16877, 16877, 18000, 18000, 22300, 17200, 18000, 18000,
18200, 18000, 17300, 14700, 14700, 4000, 4000); /* исходные данные */


var sortedNr = new Array(), z = 0;

sortedNr = outlier(nr);
document.body.innerHTML = "Исходные числа: " + nr  + "<BR />\n";
document.body.innerHTML += "<B><U>Числа, которые попадут в статистику:</U></B> " + sortedNr + "<BR />\n";

for (var x = 0; x < sortedNr.length; x++) {
   z += sortedNr[x];
}
z = z / sortedNr.length;

document.body.innerHTML += "<B><U>Средний показатель:</U></B> " + z + "<BR />\n";

По исполнении программы получаем следующее:

Исходные числа: 4000, 4000, 4500, 4500, 14700, 14700, 15345, 16877, 16877, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17200, 17300, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 18000, 18000, 18000, 18000, 18000, 18200, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 22300, 23000, 35000, 65000
Числа, которые попадут в статистику: 4000, 4000, 4500, 4500, 14700, 14700, 16877, 16877, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17000, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 17437, 18000, 18000, 18000, 18000, 18000, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500, 21500
Средний показатель: 17013.634615384617

Как и ожидалось, зарплаты 65000 рублей, 35000 рублей оказались выбросами. Средняя зарплата составляет 17013.63 (рубля), что на 7.03% ниже показателя, рассчитанного раннее.

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