Python в анализе данных

Принимать решения без данных это как играть в русскую рулетку: повезет – не повезет. Поэтому данные нужно копить с первого дня жизни бизнеса. Данные это сырье для бизнеса, и по началу они будут помогать принимать решения без особых затрат. Но когда количество данных перевалит за 1 Tb, бизнесу станет сложнее быстро выжимать фичи по векторам на регулярной основе. Помочь может визуализация данных. Имея в багаже математическую базу и возможности Python при использовании библиотек matplotlib, seaborn и plotly, можно покрыть большинство потребностей по визуализации графиков для руководства и для принятия решений.

Существует множество инструментов для визуализации данных: R, Python, JS, Matlab, Scala и Java. R это больше язык для исследователей и студентов, поэтому у него на данный момент больше полезных библиотек для визуализации, чем у Python. Но Python лучше для дальнейшей интеграции разработки.

На больших проектах, где положительные изменения дают 1%<, аналитика необходима. Как минимум, нужно не только проверить результаты a/b теста, но и как эти две группы пользователей вели себя до эксперимента. И отсечь влияние других экспериментов, прошлых и нынешних.

Примерный пайплайн такой:
— проверяем данные на нормальность;
— проверяем отличия с помощью статистического теста;
— доверительным интервалом оцениваем масштаб (среднее при нормальности или медиана для ненормальности данных);
— сравниваем с прошлым поведением групп пользователей;

Данных для визуализации на Python должно быть много, иначе нет смысла в распределенном анализе. Если данных много, то вы почти всегда получите маленькое p-value, и вам останется только проработать нормальность данных, их независимость и т.п. Для расчёт размера выборки нужны тесты для анализа мощности (power tests). На маленьких выборках статистические тесты могут быть менее эффективны, чем экспертная оценка, а на больших данных будут видны даже минимальные отклонение от нормальности. Также, при малой выборке мы не можем использовать центральную предельную теорему.

Основная библиотека для визуализации это Matplotlib. Отмечу, что Matplotlib пусть и очень популярная, но достаточно старая и сложная библиотека, и для комфортной работы лучше использовать API поверх Matplotlib, такие как Seaborn, у которого много своих способов построения графиков. При том, достаточно эстетичных. Достаточно добавить sns.set(), посмотрим на примере:

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
 
from matplotlib import pyplot as plt
import seaborn as sns; sns.set()
norm_data = np.random.normal(size = 1000, loc = 0, scale = 1)
plt.hist(norm_data)
plt.show()
Слева гистрограмма в исполнении Matplotlib, справа в исполнении Seaborn.

Мы построили наш первый график, используя Python. Конечно, хочется быстрее перейти от работы со списками к работе с массивами значений. Но для начала немного освежим теорию математической статистики:

Нулевая гипотеза всегда консервативна (проще проверяется), а альтернативная гипотеза это ненормальное распределение. В первую очередь проверяется нормальность данных, так как для среднего и стандартного отклонения нормальное распределение может быть лишь одно, ненормальных распределений возможно бесконечное количество. Проверка нормальности возможна тестом Shapiro-Wilk, который проверяет нулевую гипотезу о происхождении данных из нормального распределения.

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


Если не хотим разбираться с нормальным распределением, то используем статистический метод бустрэппинг.

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

  • Среднее арифметическое значение в данных. Идея в том, что если взять любое типичное значение из набора данных, оно будет похоже на среднее значение. Не самый надежный способ.
  • Медиана. В отличии от среднего арифметического, все значения сортируются в порядке возрастания и в качестве среднего значения берется то, что окажется в середине списка. Считается более надежным подходом. Если в списке четное количество значений, то высчитывается среднее между двумя значениями из центра отсортированного набора данных.
  • Мода. Значение, которое можно встретить в данных чаще остальных. Это менее среднее значение, чем два предыдущих. Скорее, это наиболее тяжеловесный фактор, который влияет на среднее значение в данных.
Перейдем к проверке статистической значимости. Допустим, мы выгрузили данные по транзакциям за месяц и хотим понять, были ли отклонения от нормального поведения:
import matplotlib
matplotlib.use('TkAgg')
import scipy.stats as stats
from matplotlib import pyplot
 
x = stats.norm.rvs(loc=5, scale=3, size=543)
print (stats.shapiro(x))
pyplot.hist(x)
pyplot.show()

Я осознанно не использую seed, так как чем больше вариативность полученных вами результатов, тем лучше. У меня возвращено 2 значения: значение статистики теста, и связанное с ним значение p-value, в моем случае получилось 0.011658577248454094. А так как 0.0116 < 0.05, и для отклонения нулевой гипотезы p-value должно быть не выше альфы 0,05, то у нас есть веские доказательства того, что мы отвергаем нулевую гипотезу на уровне значимости 0,05.

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

Меняем Критерий Шапиро-Уилка на тест Андерсона, print (stats.anderson(x)), проверяем еще раз, что данные в выборке более менее нормально распределены. За тестом Андерсона Дарлинга часто используют w^2 Мизеса. Результат можно проверить даже визуально:

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

Используем для этого ANOVA (дисперсионный анализ) из библиотеки Scipy, командой stats.f_oneway. Нулевая гипотеза ANOVA предполагает, что мат. ожидания совпадают. Если t-критерий Стьюдента используется для сравнения среднего значения в двух независимых или зависимых группах, то f-критерий проверяет, есть ли вообще разница. Можно использовать для большего количества выборок, чем 2. Разумеется, ANOVA не является f-тестом в полной мере, это модель регрессии и считается обобщенной линейной моделью (GLM). ANOVA используется для сравнения среднего значения какого-то признака в независимых группах.

import matplotlib
matplotlib.use('TkAgg')
import scipy.stats as stats
 
a = [2,3,1,4,3,4,2,4,-1,32,12,53,2,2,3,2.3,2,4.2,3,32,1]
b = [3,4,-1,3,4,43,4,14,2.3,1,3,2.3,12,42,2.4,3,4,1,4,1,2]
print (stats.f_oneway(a,b))

Получаем F-статистику F_onewayResult(statistic=0.0386380063725391, pvalue=0.8451628704190369), что говорит нам, больше ли дисперсия между группами, чем дисперсия внутри групп, и вычисляет вероятность наблюдения этого коэффициента дисперсии, используя F-распределение. Конечно, для научных публикаций данных недостаточно, нет степеней свободы. Но заветный P-value мы получили и теперь знаем, что раз 0.8451628704190369 > 0.05, то работа продажников явно завязана не только на тех данных, что у нас имеются. У нас отказ от нулевой гипотезы, так как данные не выглядят нормально. Нулевая гипотеза a = b, альтернативная a ≠ b.

Сравним средние двух выборок с помощью T-test. Мы хотим узнать, есть ли различия в двух группах данных, пусть это будут результаты A/B теста для туториалов в мобильном приложении. Для этого нужно интерпретировать статистическое значение в двустороннем тесте с примерно нормальным распределением, что означает, что нулевая гипотеза может быть отвергнута, когда средние значения двух выборок слишком отличаются. В R мы использовали функцию t.test() для простого t-теста Стьюдента, в Python у нас больше возможностей. Можно выполнить как односторонний, так и двусторонний t-test в Python. Если у вас много шума в данных, не забудьте сделать дисперсию. Стьюдента для независимых выборок считают с равными дисперсиями.

У двустороннего теста и p-value получится в два раза больше, чем у одностороннего, поэтому двусторонний тест имеет более строгие критерии для отклонения нулевой гипотезы. Гипотетически, из двустороннего p-value можно получить одностороннее, но при правильно проведенном тесте не должно возникнуть такой необходимости. При двустороннем тесте мы делим p-value 0.05 на два, и отдаем по 0.025 на положительный и отрицательный концы распределения. При одностороннем тесте весь p-value 0.05 располагается в одном конце распределения. Так как второй конец распределения игнорируется, то есть вероятность ошибки: создав новый туториал, можно протестировать односторонним тестом, лучше ли новый туториал предыдущего. Но информация о том, хуже ли новый туториал предыдущего, будет проигнорирована. Но если новый туториал рассчитан на другую аудиторию и мы точно знаем, что он не может быть хуже, то односторонний тест вам подходит и даст бОльшую точность.

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

import matplotlib
matplotlib.use('TkAgg')
from scipy import stats
 
a = [742,148,423,424,122,432,-1,232,243,332,213]
b = [-1,3,4,2,1,3,2,4,1,2]
print (stats.ttest_ind(a,b))

Результаты завязаны на проблеме Беренса-Фишера, так как точного решения не существует, но вероятность позволяет нам сделать вывод. Если сделать поправку на то, что при маленькой выборке никак не сгруппированных данных у нас большая дисперсия (проверяем дисперсию командой print(np.var(a)) ), то качество данных можно поставить под сомнение. Если данные не распределены нормально, нужен критерий Манна-Уитни, также известный как Критерий Уилкоксона. Выборка у нас небольшая, поэтому Манна-Уитни вполне подойдет, ранги не будут сильно пересекаться.

import matplotlib
matplotlib.use('TkAgg')
from scipy import stats
 
a = [742, 148, 423, 424, 122, 432, -1, 232, 243, 332, 213]
b = [-1, 3, 4, 2, 1, 3, 2, 4, 1, 2]
 
u, p_value = stats.mannwhitneyu(a, b)
print("two-sample wilcoxon-test", p_value)

P-value стал 0.0007438622219910575. Сравнивать выборки можно и визуально:

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from scipy.stats import ttest_ind
import matplotlib.pyplot as plt
a = np.random.normal(loc=0,scale=24,size=4454)
b = np.random.normal(loc=-1,scale=1,size=7643)
 
print(ttest_ind(a,b))
 
plt.hist(a, bins=24, color='g', alpha=0.75)
plt.hist(b, bins=24, color='y', alpha=0.55)
plt.show()
Получаем statistic=4.3337700320925885, pvalue=1.4776127369400805e-05.
Что намного меньше 0.05, т.е. мы отклоняем нулевую гипотезу критерия Стьюдента про равенство средних. У интернет-магазинов слишком разные данные, нужна сегментация .

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

import matplotlib
matplotlib.use('TkAgg')
from scipy import stats
 
from scipy import stats
a = stats.norm.rvs(loc = 5,scale = 10,size = 23000)
b = stats.norm.rvs(loc = 5,scale = 10,size = 23425)
print stats.ttest_ind(a,b)

Получаем statistic=-0.7043486133916781, pvalue=0.4812192321148787, что намного больше 0,05. А так как р > 0.05 мы считаем маловероятной ошибкой, а р <= 0.05 высоковероятной, то две выборки можно считать равными. Также, для проверки равенства средних подходят Критерий Манна-Уитни, Уилкоксона, Краскера-Уолласа.

Визуализация

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
 
sns.set()
data = np.random.multivariate_normal([0, 0], [[43, 2], [5, 1.2]],size=25000)
data = pd.DataFrame(data, columns=['x', 'y'])
 
for col in 'xy':
    sns.kdeplot(data[col], bw=.2, shade=False, label="MAU"),
plt.show()

График выше прекрасно подходит для визуального сравнения двух выборок. Доверительный интервал находится между 5 и 95 процентым квантилем, 90% доверительный интервал это двусторонний критерий между 5 и 95.

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
 
plt.style.use('classic')
plt.style.use('seaborn-whitegrid')
data = np.random.multivariate_normal([0, 0], [[3.4, 1.87], [2.8, 1.44]],size=25000)
data = pd.DataFrame(data, columns=['x', 'y'])
sns.distplot(data['x'])
sns.distplot(data['y']);
 
plt.show()

Представленные выше графики достаточно стандартны и вы неоднократно их строили или, по крайней мере, видели. А вот следующий график, Jointplot, уже куда интереснее. Он совмещает в себе гистограммы по x и y, и включает типичный график рассеяния. Получается своеобразный куб из гистограмм.

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
 
plt.style.use('classic')
plt.style.use('seaborn-whitegrid')
data = np.random.multivariate_normal([0, 0], [[43, 2], [5, 1.2]],size=25000)
data = pd.DataFrame(data, columns=['x', 'y'])
with sns.axes_style('white'):
    sns.jointplot("x", "y", data, kind='kde');
 
plt.show()

Получилось! Далее построим диаграмму рассеивания.

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
a = np.random.rand(20)
b = [3, 4, 3.4, 6, 7, 8, 9, 10, 4, 0.3, 4.2, 4, 23, 3, 33, 3, 1, 4, 0.1, 4.2]
colors = np.random.rand(20)
plt.scatter(a, b, c=colors, s=100, alpha=0.65, marker=(5, 0))
plt.show()

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

И Box Plot, куда же без него. Работает с группой из минимум пяти чисел: минимум, первый квартиль, медиана, третий квартиль и максимум. Усы идут от каждого квартиля до минимума или максимума.

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
 
b = [1, 2, 3, 4, 3.4, 6, 7, 8, 9, 8, 4, 0.3, 4.2, 14, 21, 1, -8]
df = pd.DataFrame(b)
sns.boxplot(data=df)
plt.show()

 А теперь немного 3D, бизнес такое любит:

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
 
x = np.arange(-2, 5, 0.85)
xlen = len(x)
y = np.arange(-5, 2, 0.25)
ylen = len(y)
x, y = np.meshgrid(x, y)
r = np.sqrt(x**2 + y**2)
z = np.sin(r * 1.3)
 
ax = plt.figure(figsize=(8,6))
ax = ax.add_subplot(1,1,1, projection='3d')
ax.plot_surface(x, y, z, cmap=cm.coolwarm, edgecolor='black', linewidth=0.23, antialiased=True)
 
plt.show()

Python Seaborn это лучшее решение для визуализации привлекательных статистических диаграмм. Если же ваша цель это интерактивные графики в вебе, то Python Bokeh, Pygal, Plotly это ваш выбор. Изучайте Python и мат. стат, и ваш продуктовый дизайн сильно вырастет.

20 комментариев

  1. Mikhail Neshchadimov

    Существует ли специфика анализа данных для финтеха?

    • Цветков Максим (Author)

      Банкинг это P&L бизнес, и задачи все идут по тебе прибыли и убытков. У финтеха данных много, но данные всегда очень грязные и обрывочные. Но можно партнериться к другими банками для обмена данными (с учетом защиты персональных данных) и телекомами. Это дает некоторые очевидные преимущества: например, чем старше сим-карта клиента, тем больше шанс выдачи кредита.

      Задачу для анализа всегда ставит бизнес, и постановка задачи зачастую довольно сложная. Начиная от очевидных хотелок про определение оттока физических лиц (в России банкам очень выгодно, когда у клиента есть дебетовый продукт, на этом банк хорошо зарабатывает), заканчивая психотипированием. Почти наверняка будут задачи про уменьшение универсальности, персонализацию предложения каждому клиенту. Даже в рамках сегмента будут неоптимальные соотношения предложения/ожидания для клиентов на разных концах выборки. Поэтому всегда будут задачи по построению up-sale и cross-sale исходя из соотношения трат на негативные (аренда, коммуналка, штрафы) и позитивные (новый гардероб, походы в кино, цирк, горы).

      И классика с принятием решения о выдаче кредита. Банки хотят понимать, заплатит ли потенциальный заемщик по кредиту или нет. Это классическая статистика с действием по умолчанию: если не заплатит, то не выдавать кредит (классический банк). Или наоборот, по умолчанию выдавать кредит всем (микро-кредитование). Если нулевая гипотеза что кредит не выдаем, то ошибка первого рода будет выдать кредит и получить клиента, который не платит.

      Вторая часть задач про маркетинг в Интернете. Выкатывать рекламу на всех пользователей неэффективно, качество лидов по такой рекламе низкое, у банков будет много отказов на выдачу кредита + неэффективные предложения клиентам, и реклама не окупится. Поэтому огромное внимания уделяется таргетингу. Это классический рекомендательный контент на точках интереса (заправки, ТЦ, аэропорты, университеты), для которого понадобится копить события (JSON), сжимать в батчи и отправлять по https на ваши веб-сервера. Дальше брать ширину и долготу, учесть искажения на полюсах от проекции Меркатора и переходы времени по Гринвичу, «рисовать» гексагон или квадрат для определения области нахождения пользователя. Определять по КЛАДРу, ФИАСу, ISO 3166 или GeoNames, где пользователь находится и что есть вокруг, и после этого вступает в дело рекомендательная система.

      Примерно такие задачи будут первостепенны. Следующий шаг это R, Zeppelin, Presto, Python.

  2. Михаил Боршевитский

    Здравствуйте, благодарю за статью. Подскажите по критерию для следующей ситуации: делаю своего рода карточную сортировку на 20 админах, даю список пунктов меню и прошу выбрать те, которые им понятны и нужны в меню. Есть ли способы это подсчитать?

    • Цветков Максим (Author)

      Я так понимаю, на выходе у вас бинарные данные 1 или 0, тогда нужно подсчитать согласованность. Я бы начал с критерия Стюарта-Максвелла, потом Q-критерий Кохрана, и критерий маргинальной однородности.

      У Q-критерия Кохрана нулевая гипотеза это пропорции «успешных» результатов одинаковы во всех группах. Альтернативная гипотеза это хотя бы одна группа имеет отличия в пропорциях. Нулевая гипотеза отклоняется, когда вычисленное критическое значение Q больше критического значения хи-квадрата. При отклонении нулевой гипотезы выполните парные контрольные Q-тесты Кохрана для выявления отличий.

      В зависимости от данных, можно еще обратиться к хи-квадрату Пирсона. Вот простой пример: мы подкидываем монетку 100 раз, и получаем 45 орлов и 55 решек. Ожидаемое 50 на 50, это будет нулевая гипотеза. У хи-квадрата принимается или отклоняется нулевая гипотеза по степеням свободы (df), которые можно подсмотреть в готовых табличках. У нас две стороны монетки, поэтому из 2 мы вычитаем 1 и получаем одну степень свободы. Далее выбираем 0.05 (95%), и получаем по таблице значение 3.841. Далее немного математики, для отклонения нулевой гипотезы нужно получить значение выше 3.841.

      Считаем так:
      (55 - 50)² / 50 = 25 / 50
      (45 - 50)² / 50 = 25 / 50
      50/50 = 1

      у нас одна степень свободы, и полученное значение 1 < 3.841, значит мы принимаем нулевую гипотезу/не может отклонить нулевую гипотезу (кому как удобнее интерпретировать). Попробуем отклонить нулевую гипотезу: монетку подбросили 100 раз, 34 орлов и 66 решек.
      (34 - 50)² / 50 = 256 / 50
      (66 - 50)² / 50 = 256 / 50
      512 / 50 = 10.24

      10.24 > 3.841, мы отклоняем нулевую гипотезу H0, наши данные статистически значимы.

  3. Alexey Sarapulov

    Не могли бы привести пример классического процесса проверки а/б теста?

    • Цветков Максим (Author)

      Берем данные. У нас есть набор данных с параметрами конверсии до участия дизайнера в проработке лендинга и после, парная выборка. На первый взгляд надо использовать парный t-test, достаточно рассмотреть разность. Но самое первое это проверка на выбросы:

      import matplotlib
      matplotlib.use('TkAgg')
      import matplotlib.pyplot as plt
      import pandas as pd
       
      df = pd.read_csv("Downloads/testData.csv")
      df[['Manager_design', 'Designers_design']].plot(kind='box')
      print (df.head())
      plt.show('boxplot_outliers.png')

      По box-plot видно, что в нашем наборе данных отсутствуют какие-либо существенные выбросы. Следующий шаг это проверка распределения. Для двух зависимых выборок необходимо провести проверку нормальности на различия между двумя наборами данных. Для этого можно использовать гистограмму, Q-Q plot, или статистические тесты.

      df = pd.read_csv("Downloads/testData.csv")
      print (df.head())
      df['final_design'] = df['Manager_design'] - df['Designers_design']
      plt.show(df['final_design'].plot(kind='hist'))


      Видим, что распределение нормальное. Для надежности посмотрим на результаты теста Шапиро-Вилка на нормальность print (stats.shapiro(df['final_design'])). Получаем W = 0.9910880327224731 и P-value = 0.1491156369447708. Распределение все же нормальное, так как результаты теста незначительные. Если бы распределение было ненормальное, мы перешли бы на тест Вилкоксона.

      Далее переходим к парному T-test. Его результаты statistic=-8.062787757694716, pvalue=3.5364610751401186e-14. Полученные данные являются статистически значимыми. Можно отвергнуть нулевую гипотезу в поддержку альтернативы. Вмешательство дизайнера в процесс проработки лендинга имело влияние, в данном случае позитивное.

      print (stats.ttest_rel(df['Manager_design'], df['Designers_design']))

      Строгой нормальности обычно не нужно, а тесты для проверки нормальности достаточно строгие. Надо сделать ремарку, T-test’ов много разных.

      • Alexey Sarapulov

        Спасибо, самое простое объяснение, что я видел в рунете)) но, честно говоря, я рассчитывал на ответ про сравнение множества когорот…

        • Цветков Максим (Author)

          Тогда вам нужен тест ANOVA (почти как t-test) для проверки данных в целом, поиска аномальных активностей. С t-test у него общего регрессионная модель (GLM). Для доверия результатам теста надо: однородность дисперсии, нормальность данных, равное количество наблюдений в каждой группе и независимость наблюдений. Если кол-во наблюдений в группах значительно разнится, то нужно использовать Kruskal-Wallis H-test или Welch’s ANOVA.

          Вот данные. Мы хотим сравнить средние значения 3+ выборок с помощью F-распределения. Будем использовать stats.f_oneway().

          import matplotlib
          matplotlib.use('TkAgg')
          import pandas as pd
          import scipy.stats as stats
           
          df = pd.read_csv("/Downloads/testData2.csv")
          iOS = df.iOS.dropna()
          Android = df.Android.dropna()
          Windows = df.Windows.dropna()
          print (stats.f_oneway(iOS, Android, Windows))

          Получаем F_onewayResult(statistic=7.3488433965696975, pvalue=0.000674137267723654). В качестве альтернативы можно было использовать fligner-killeen test, он даже лучше.

          P < 0,05. А если р < 0,05, то мы считаем, что можно отвергнуть нулевую гипотезу. Нулевая гипотеза (H0) состоит в том, что нет разницы между группами, а альтернативная гипотеза (H1) про наличие различий. Различия есть, и следующая задача это определить, какие группы отличаются друг от друга. Но перед тестом следовало бы поработать с данными, по графикам видно, что есть выбросы.

          sns.distplot(iOS, rug=True, hist=True)
          sns.distplot(Android, rug=True, hist=True)
          sns.distplot(Windows, rug=True, hist=True)
          plt.show()
           
          df2 = df.drop('user', 1)
          plt.hist(df2, edgecolor='k', alpha=0.6)
          plt.show()
           
          plt.plot(df2)
          plt.show()

          • Новичков Игорь

            Спасибо! Но ведь надо перед этим проверить данные? именно те что в табличной форме импортированы.

          • Цветков Максим (Author)
            objects = pd.read_csv('folder/testData2.csv', delimiter=',', header = 0, index_col=False)
            print (objects.head())

            Да, надо. Узнать количество строк можно командой print (len(objects)), количество столбцов print (objects.shape), типы данных print (objects.dtypes).
            Далее идет описательная статистика, команда print (objects.describe(include="all")). Получаем описание в рамках порядковой (данные для сравнения), количественной (числа) и номинальной шкале (числа не для сравнения).

            std это стандартное отклонение (корень из дисперсии), mean это среднее, 50% (медиана) это квантиль, 25% и 50% это квартили. Смотрим на данные и ищем аномалии.

            Еще нужно смотреть плотность данных, тут поможет гистограмма на примере колонки Windows

            matplotlib.style.use('ggplot')
            objects['Windows'].hist();
            plt.show()


            Видим выбросы справа. И это критично, как и колокообразная форма (так как наблюдений больше 150). Не критичное это отклонения от симметрии.

  4. Marker Frank

    Получается что p-value это вероятность правильного решения, но ведь даже ошибка в пяти случаях из ста это могут быть миллионы долларов, или 5 убитых пациентов, неужели все полагаются на 5% допуска ошибки без дополнительных способов проверки?

    • Цветков Максим (Author)

      Если полученное значение ниже 0.05 мы отклоняем H0 гипотезу и считаем, что разница является статистически значимой. Но на p-value влияет множество выбросов из данных, поэтому часто используют оценку p-value с помощью bootstrap. И тогда возможна ситуация, когда полученные p-value сильно выше 0.05. Но если провести bootstrap для p-value и оценить его 50 квантиль (медиана), то он может быть равен p<0.05, и можно отклонить нулевую гипотезу. Так часто валидируют эксперименты. Либо взять за правило p-value не 0.05, а 0.01, получается более строгий порог для "отвергнуть основную гипотезу".

      При проектировании критически важной инфраструктуры может быть и p-value < 10^-5.

  5. Василий Тиньк

    Здравствуйте, у меня есть множество наблюдений в разных группах, по каким принципам принято полученные наблюдения раскидывать по когортам?

    • Цветков Максим (Author)

      Предположим, что наблюдения схожие: тогда можно использовать иерархический кластерный анализ, он как раз разбивает объекты на группы. Кластер это попросту скопление объектов, близких по своим свойствам. Близость свойств между объектами определяют разными алгоритмами, обычно это евклидово расстояние или block. Евклидово позволяет делать большое расстояние гигантским, так как различия возводятся в квадрат. Block не возводит в квадрат, и большие различия получаются менее значимы.

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

      import matplotlib
      matplotlib.use('TkAgg')
      import pandas as pd
      import matplotlib.pyplot as plt
      import scipy.cluster.hierarchy as sch
       
      objects = pd.read_csv('/Downloads/data3.csv', delimiter=',', index_col=False)
      print (objects.head())
       
      print objects.shape
      dendrogram = sch.dendrogram(sch.linkage(objects, method='ward'))
      plt.show()

  6. М. Антон

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

    • Цветков Максим (Author)

      В общем случае это ваша текущая конверсия (до начала теста), ожидаемый рост конверсии (например, экспертно считаем что конверсия должна подскочить на 20%), p-value (вероятность ошибки). При этом почти всегда берут 5% p-value и 80% мощность.

      Za :
      p-value 5%
      2-sided 1.96
      1-sided 1.65

      Либо
      p-value 1%
      2-sided 2.58
      1-sided 2.33

      Либо
      p-value 0.1%
      2-sided 3.29

      И Z1−β:
      Мощность: 80% (Z1−β = 0.84), 85% (Z1−β = 1.04), 90% (Z1−β = 1.28), 95% (Z1−β = 1.64)


      Вот одна из формул из моей практики, подразумеваются равные выборки. Сначала считаем дисперсию, текущая конверсия 50%, и ожидаемая 50% + (20% / 2) = 60%.
      0.5(1 – 0.5) + 0.6(1 – 0.6) = 0.25 + 0.24 = 0.49.

      Теперь берем уровень достоверности 95%, это дает нам значения Za = 1,96.
      1. 0.49/0.01 = 49 * 2 = 98
      2. (1.96 + 0.8)² = 7.6176
      3. Объем выборки = 98 * 7.6176 = 746 (делим на контрольную и тестируемую выборки)

  7. Pavel

    >> У меня возвращено 2 значения: статистика хи-квадрата и связанное с ним значение p-value, в моем случае получилось 0.011658577248454094.

    Как связана статистика хи-квадрат с тестом Шапиро-Уилка?

    >> А так как 0.0116 < 0.05, и для отклонения нулевой гипотезы p-value должно быть не выше альфы 0,05, то у нас есть веские доказательства того, что мы отвергаем нулевую гипотезу на уровне значимости 0,05. Вывод: в первом приближении, отклонений от нормального поведения в транзакциях не выявлено.

    Нулевая гипотеза теста H0: X ~ N(mu, sigma). Ваше p-значение получилось меньше альфы, не значит ли это, что нулевая гипотеза отклоняется в пользу альтернативной, что распределение данных существенно отличается от нормального?

    • Цветков Максим (Author)

      Как связана статистика хи-квадрат с тестом Шапиро-Уилка?

      С помощью Шапиро Уилко я отвечаю на вопрос, является ли выборка нормально распределенной. А критерий хи-квадрата помогает понять, являются ли наблюдения в двух группах независимыми друг от друга. По результатам, допустим, можно выбрать t-test для понимания, был ли завод более эффективен в 2020 году чем в 2010 году.

      Нулевая гипотеза теста H0: X ~ N(mu, sigma). Ваше p-значение получилось меньше альфы, не значит ли это, что нулевая гипотеза отклоняется в пользу альтернативной, что распределение данных существенно отличается от нормального?

      Все верно. Так как полученное p-value меньше критического значения, с вероятностью 95% отклоняем нулевую гипотезу о равенстве средних, это так. Если p-value ≤ α: данные не соответствуют нормальному распределению и мы отклоняем H0.

      Значение p-value > α: не отклоняем нулевую гипотезу, так как значение p больше, чем уровень значимости. При этом мы не можем сделать вывод, что данные не соответствуют нормальному распределению. И нельзя сделать вывод, что данные соответствуют нормальному распределению.

      Но как в анекдоте: есть нюанс. Тест проверяет нулевую гипотезу, что наша выборка была извлечена из генеральной совокупности с нормальным распределением. А вот насколько отклонение от нормальности существенно с точки зрения применения параметрики, часто решается исходя из полученных графиков/данных. На выборках небольшого объема, но сильно отличающимся от нормального распределения, мы можем себе позволить р-value больше 0,05, а вот на больших выборках и небольшие отличия будут значимы на уровне р<0,05. Значение p-value не зависит от альфы, а принятие или отклонение Н0 очень даже зависит.

      И опять же, я могу использовать критерий Колмогорова-Смирнова, с которым игрушечные выборки будут проходить тест на нормальность, даже если они явно ненормальные и это видно на глаз. И наоборот, на огромных выборках будет отвергнута гипотеза о нормальности данных, хотя на b2c проектах небольшие отклонения от нормальности не являются проблемой.

  8. Kirill V. Nikulin

    Здравствуйте, а как по boxplot понять распределение данных? Или он не для этого?

    • Цветков Максим (Author)

      Лучше использовать Violin plot, он нагляднее показывает распределение. По нему проще понять, где сконцентрировано больше данных, вокруг медианы или около максимума/минимума.

      import matplotlib
      matplotlib.use('TkAgg')
      import pandas as pd
      import numpy as np
      import seaborn as sns
      import matplotlib.pyplot as plt
       
      rs = np.random.RandomState(42)
      data = rs.randn(1000, 3) * [2, 0.564, 1.5] + [0, 1, -1]
      data[:, :32] * -5 + 10
      df = pd.DataFrame(data)
      print(df)
       
      sns.violinplot(x='variable', y='value', data=pd.melt(df), scatter_kws={"s": 100}, bw=0.3,  kind="violin", palette = "Blues")
      plt.violinplot(df.T)
      plt.xlabel('Day')
      plt.ylabel('CPC')
      plt.show()

      Классически идет с черной толстой полосой в центре, которая показывает интервал между четвертями. Эта полоса перетекает в тонкую черную линию, которая визуализирует 95% доверительные интервалы, и белая точка в центре это медиана.

«Взаимодействуя с данным сайтом, вы, как пользователь, автоматически даете согласие согласие на обработку персональных данных» Согласие

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.