Многомерный анализ и визуализация в Python
В наши дни стало обычной практикой для компаний и предприятий собирать как можно больше информации, даже если варианты использования таких данных неизвестны во время сбора — надежда состоит в том, чтобы понять и использовать данные в какой-то момент в будущем. будущее. Как только такие наборы данных станут доступны, люди, ориентированные на данные, будут углубляться в данные в поисках скрытых закономерностей и взаимосвязей внутри данных. Одним из инструментов обнаружения таких скрытых закономерностей в данных является многофакторный анализ.
Многомерный анализ включает в себя анализ взаимосвязей между несколькими переменными (т. е. многомерными данными) и понимание того, как они влияют друг на друга. Это важный инструмент, который помогает нам лучше понимать сложные наборы данных, чтобы принимать основанные на данных и обоснованные решения. Если вас интересует анализ влияния только одной переменной за раз, это можно сделать с помощью одномерного анализа, о котором я рассказал в этой статье.
Теперь, когда мы знакомы с многомерными данными, мы можем определить одномерные данные как частный случай многомерных данных, где данные состоят только из одной переменной. Точно так же двумерные данные состоят из двух переменных и так далее.
В этом посте мы обсудим двумерный/многомерный анализ как числовых, так и категориальных переменных. Поэтому давайте быстро вспомним разницу между этими двумя типами переменных, а затем мы можем перейти к анализу.
- Числовые переменные. Представляют измеримую величину, которая может быть либо непрерывной, либо дискретной переменной. Непрерывные могут принимать любое значение в определенном диапазоне (например, рост, вес и т. д.), в то время как дискретные числовые переменные могут принимать только определенные значения в пределах диапазона (например, количество детей, количество автомобилей на парковке и т. д.). )
- Категориальные переменные. Представляют группу (или категорию) и могут принимать ограниченное количество значений, например марки автомобилей, породы собак и т. д.
Теперь, когда мы понимаем разницу между этими двумя типами переменных, мы можем перейти к самому анализу.
Я организовал этот пост в формате серии вопросов и ответов, которые лично я считаю эффективным методом обучения. Я также включил ссылку на блокнот, который я использовал для создания этого упражнения ближе к концу. Не стесняйтесь скачивать и практиковаться после прочтения этого поста!
Давайте начнем!
(Все изображения, если не указано иное, принадлежат автору.)
Набор данных
Чтобы практиковать многофакторный анализ, мы будем использовать набор данных из Репозитория машинного обучения UCI (CC BY 4.0), который включает цены на автомобили и набор свойств автомобиля, связанных с ценой каждого автомобиля. Для упрощения процесса я почистил и отфильтровал данные, которые можно скачать по этой ссылке.
Давайте начнем с импорта библиотек, которые мы будем использовать сегодня, затем мы прочитаем набор данных в фрейм данных и посмотрим на 5 верхних строк фрейма данных, чтобы ознакомиться с данными.
# Import libraries import numpy as np import pandas as pd import seaborn as sns from scipy import stats import matplotlib.pyplot as plt %matplotlib inline # Show all columns/rows of the dataframe pd.set_option("display.max_columns", None) pd.set_option("display.max_rows", None) # Read the data df = pd.read_csv('auto-cleaned.csv') # Return top 5 rows of the dataframe df.head()
Полученные результаты:
Столбец, который мы будем использовать в этом посте, говорит сам за себя, поэтому не беспокойтесь о понимании всех столбцов на этом этапе.
Перейдем к анализу!
Численный двумерный анализ
Начнем со случая двумерных данных, состоящих только из двух переменных. Цель двумерного анализа - понять взаимосвязь между двумя переменными. Существуют различные статистические методы, которые можно использовать для анализа двумерных данных, и использование диаграмм рассеяния является одним из наиболее распространенных. Давайте посмотрим, как работают диаграммы рассеяния.
Вопрос 1:
Какая связь между ценой и объемом двигателя? Можно было бы интуитивно ожидать, что автомобили с более мощными двигателями будут иметь более высокие цены (при прочих равных условиях), но давайте посмотрим, подтверждают ли это данные. Создайте диаграмму рассеяния с ценой по оси x и объемом двигателя по оси y.
Ответ:
# Create the scatterplot sns.regplot(data = df, x = 'price', y = 'engine-size', fit_reg = False) plt.show()
Полученные результаты:
Как мы видим, в наших данных наблюдается положительная связь между ценой и объемом двигателя. Обратите внимание, что это не подразумевает причинно-следственную связь (независимо от того, правильно это или неправильно), а просто показывает положительную корреляцию между ними. Давайте добавим значения корреляции, чтобы иметь количественную меру для нашей справки.
Вопрос 2:
Возвращает корреляцию между ценой и другими переменными в порядке убывания.
Ответ:
# Create the overall correlation corr = np.round(df.corr(numeric_only = True), 2) # Return correlation only with price price_corr = corr['price'].sort_values(ascending = False) price_corr
Полученные результаты:
Результаты подтверждают положительную корреляцию, которую мы наблюдали на диаграмме рассеяния между ценой и объемом двигателя. Давайте попробуем пойти на один уровень глубже и посмотреть на вариации данных.
Неоднородность и стратификация
Неоднородность данных относится к вариациям в наборе данных. Например, наш набор данных состоит из различных типов кузова, таких как седан, хэтчбек, универсал, кабриолет и т. д. Ожидаем ли мы, что корреляция между ценой и объемом двигателя будет одинаковой для всех этих типов кузова? Например, дополнительная готовность клиентов платить за двигатели большего размера в кабриолетах может быть выше по сравнению с универсалами, которые в основном используются семьями. Давайте рассмотрим эту гипотезу и посмотрим, существует ли такая вариация в зависимости от телосложения, расслоив наши данные по стилям телосложения.
Вопрос 3:
Набор данных включает цены на автомобили с различными типами кузова, как указано в столбце «тип кузова». Сколько строк на класс в наборе данных?
Ответ:
# Apply value_counts to the df['class'] column df['body-style'].value_counts()
Полученные результаты:
По результатам выделяют пять классов.
Вопрос 4:
Создайте диаграмму рассеяния цены по типу кузова в зависимости от объема двигателя, чтобы продемонстрировать, есть ли визуальная разница между стилями кузова.
Ответ:
sns.FacetGrid(data = df, col = 'body-style').map(plt.scatter, 'price', 'engine-size').add_legend() plt.show()
Полученные результаты:
Вот это интересно! Распределения сильно отличаются от общего распределения, которое мы наблюдали в вопросе 1, и демонстрируют визуальные различия между этими пятью типами телосложения. Все пять типов кузова демонстрируют положительную корреляцию между ценой и объемом двигателя, как и ожидалось, но наклон кажется самым высоким для кабриолетов (несмотря на меньшее количество точек данных) по сравнению с универсалами. Давайте посмотрим на числа корреляции, чтобы количественно их оценить.
Вопрос 5:
Какова корреляция между ценой и объемом двигателя для каждого из типов кузова?
Ответ:
bodies = df['body-style'].unique() for body in bodies: print(body) print(df.loc[df['body-style'] == body, ['price', 'engine-size']].corr()) print()
Результаты подтверждают наш визуальный осмотр — корреляция цены и объема двигателя положительна для всех типов кузова, причем наибольшая корреляция принадлежит кабриолетам, а наименьшая — универсалам, как мы интуитивно и ожидали. Далее мы рассмотрим категориальный двумерный анализ.
Категориальный двумерный анализ
В этом разделе мы собираемся создать аналогичный двумерный анализ, но для категориальных переменных. В статистике этот тип анализа обычно визуализируется с помощью «таблицы непредвиденных обстоятельств» (также известной как перекрестная таблица или кросс-таблица), которая отображает частоту или количество наблюдений для двух (для двумерных) или более (для многомерных) категориальных переменных. Давайте рассмотрим пример, чтобы лучше понять таблицы непредвиденных обстоятельств.
Вопрос 6:
Создайте таблицу непредвиденных обстоятельств для типа кузова автомобиля и количества цилиндров. Вы видите закономерность в результатах?
Ответ:
crosstab = pd.crosstab(df['body-style'], df['num-of-cylinders']) crosstab
Полученные результаты:
Если вы знакомы с автомобилями, наиболее распространенное количество цилиндров — 4, 6 и 8, и именно здесь мы также видим большую часть частоты в таблице. Мы также можем видеть, что большинство автомобилей в нашем наборе данных представляют собой четырехцилиндровые автомобили с типами кузова седаны и хэтчбеки, за которыми следуют универсалы. Вы заметили, что мы занимаемся мысленной арифметикой, чтобы рассчитать процент от общего количества для каждой комбинации количества цилиндров и типа кузова? Таблицы непредвиденных обстоятельств могут быть нормализованы для решения именно этой темы. Существует три подхода к нормализации такой таблицы:
- Записи в каждой строке в сумме дают 1
- Записи каждого столбца в сумме дают 1
- Записи всей таблицы в сумме дают 1
Давайте попробуем один из них в следующем вопросе.
Вопрос 7:
Создайте перекрестную таблицу, аналогичную предыдущему вопросу, нормализованную таким образом, чтобы сумма записей каждой строки равнялась 1, округленной до 2 знаков после запятой.
Ответ:
Я собираюсь продемонстрировать здесь два разных подхода в учебных целях. Первый подход использует перекрестную таблицу Pandas, а второй использует groupby.
# Approach 1 # Create the crosstab (similar to previous question) crosstab = pd.crosstab(df['body-style'], df['num-of-cylinders']) # Normalize the crosstab by row crosstab_normalized = crosstab.apply(lambda x: x/x.sum(), axis = 1) # Round the results to two decimal places round(crosstab_normalized, 2)
Полученные результаты:
# Approach 2 # Group by and count occurences using size method grouped_table = df.groupby(['body-style', 'num-of-cylinders']).size() # Pivot the results using unstack and apply the row normalization grouped_table_normalized = grouped_table.unstack().fillna(0).apply(lambda x: x/x.sum(), axis = 1) # Round the results to two decimal places round(grouped_table_normalized, 2)
Полученные результаты:
Двумерный анализ смешанных числовых и категориальных данных
Есть много случаев, когда нам нужно анализировать данные, представляющие собой смесь числовых и категориальных переменных, поэтому давайте посмотрим, как это можно сделать, теперь, когда мы знаем, как работать с каждым типом данных независимо.
Вопрос 8:
Создайте ряд диаграмм, демонстрирующих распределение цены (числовая переменная на оси Y) для различных стилей кузова (категориальная переменная на оси X).
Ответ:
# Set the figure size plt.figure(figsize = (10, 5)) # Create the boxplots sns.boxplot(x = df['body-style'], y = df['price']) plt.show()
Полученные результаты:
Я лично нахожу эту визуализацию очень информативной. Например, мы видим, что хэтчбеки имеют относительно меньший ценовой диапазон по сравнению с хардтопами или кабриолетами. Кабриолеты начинаются с более высокой цены по сравнению с другими типами кузова, и, кажется, существует хороший диапазон цен, основанный на различных характеристиках автомобиля.
Что, если бы мы хотели просто сосредоточиться на седанах и посмотреть, как меняется ценовой диапазон в зависимости от количества цилиндров? Давайте создадим боксплоты.
# Set the figure size plt.figure(figsize = (10, 5)) # Create the boxplots sns.boxplot(x = df[df['body-style'] == 'sedan']['num-of-cylinders'], y = df[df['body-style'] == 'sedan']['price']) plt.show()
Полученные результаты:
Как и ожидалось, цена увеличивается с увеличением количества цилиндров.
Блокнот с практическими вопросами
Ниже приведен блокнот с вопросами и ответами для справки и практики.
Заключение
В этом посте мы представили многомерный анализ как инструмент для поиска скрытых закономерностей в данных, а затем проработали реализацию такого анализа для числовых и категориальных переменных и их сочетания. Мы использовали инструменты визуализации, такие как диаграммы рассеяния и диаграммы, чтобы визуализировать взаимосвязь между переменными и количественно оценить такие корреляции в некоторых случаях.
Спасибо за прочтение!
Если вы нашли этот пост полезным, пожалуйста, подпишитесь на меня на Medium и подпишитесь, чтобы получать мои последние сообщения!