Прежде чем мы начнем, давайте сначала поймем важность анализа данных. Как мы уже знаем, данные собираются повсюду вокруг нас. Независимо от того, собираются ли они вручную учеными или собираются в цифровом виде, например, каждый раз, когда мы нажимаем на веб-сайт или на наше мобильное устройство. Но наличие данных еще не означает информацию. Анализ данных (также известный как наука о данных) помогает нам извлечь информацию и идеи из необработанных данных, чтобы ответить на наши вопросы. Таким образом, анализ данных играет жизненно важную роль, позволяя нам извлекать полезную информацию из данных, отвечать на вопросы и даже предсказывать будущее или неизвестное.

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

Как мы можем помочь Сэму определить лучшую цену на его машину? Давайте подумаем, как аналитик данных или специалист по данным, и четко определим некоторые из его проблем. Например, есть ли данные о ценах на другие автомобили и их характеристики? Какие особенности автомобилей влияют на их цену? Цвет? Бренд? Влияет ли мощность на цену продажи или еще что-то? Как аналитик данных или специалист по данным, вот некоторые из вопросов, над которыми мы можем начать думать.

Чтобы ответить на них, нам понадобятся некоторые данные. "Источник данных"

Примечание. Я использую Python Jupyter Notebook для выполнения своего кода. Если вы предпочитаете использовать другой инструмент или среду, не стесняйтесь это делать.

Давайте сначала разберемся с данными.

Этот набор данных имеет формат CSV, в котором каждое из значений разделяется запятыми, что упрощает импорт в большинство инструментов и приложений. Каждая строка представляет строку в наборе данных. Вот документация о том, что представляет каждый из 26 столбцов.

Хорошо, после того, как мы поняли смысл каждой функции, мы можем заметить, что 26-й атрибут — это цена. Другими словами, это наше целевое значение или метка. Это означает, что цена — это значение, которое мы хотим предсказать на основе набора данных, а предикторами должны быть все остальные перечисленные переменные, такие как символы, нормализованные убытки, производство и т. д. Таким образом, цель этого проекта — спрогнозировать цену с точки зрения других характеристик автомобиля.

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

Получение данных

Существуют различные форматы набора данных: .csv, .json, .xlsx и т. д. Набор данных может храниться в разных местах, на нашем локальном компьютере или иногда в Интернете.

В нашем случае автомобильный набор данных является онлайн-источником и имеет формат CSV (значения, разделенные запятыми).

и библиотека Pandas — это полезный инструмент, который позволяет нам считывать различные наборы данных во фрейм данных, я рекомендую вам создать виртуальную среду Python и установить pandas с помощью pip install pandas` и импортировать их в нашу записную книжку следующим образом.

# import pandas & numpy library
import pandas as pd
import numpy as np

Чтение данных

Мы можем использовать функцию pandas.read_csv() для чтения файла CSV. В скобках мы помещаем путь к файлу вместе с кавычками, чтобы панды считывали файл во фрейм данных с этого адреса. Топливный путь может быть либо URL-адресом, либо нашим локальным адресом файла.

Поскольку данные не включают заголовки, мы можем добавить аргумент headers = None внутри метода read_csv(), чтобы панды не устанавливали автоматически первую строку в качестве заголовка. И мы можем присвоить набор данных любой переменной.

# Import pandas library
import pandas as pd
# Read the online file by the URL privded above, and assign it to variable "df"
other_path = "https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMDeveloperSkillsNetwork-DA0101EN-SkillsNetwork/labs/Data%20files/auto.csv"
df = pd.read_csv(other_path, header=None)

После чтения набора данных мы можем использовать метод dataframe.head(n) для проверки верхних n строк фрейма данных, где n — целое число. В отличие от dataframe.head(n) , dataframe.tail(n) покажет нам нижние n строк фрейма данных.

# Show the first 5 rows using dataframe.head() method
print("The first 5 rows of the dataframe")
df.head(5)

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

Во-первых, мы создаем список «заголовков», который включает все имена столбцов по порядку. Затем мы используем dataframe.columns = headers, чтобы заменить заголовки созданным списком.

# create headers list
headers = ["symboling","normalized-losses","make","fuel type","aspiration", "num-of-doors","body-style", "drive wheels","engine-location","wheel-base", "length","width","height","curb-weight","engine-type", "num-of-cylinders", "engine-size","fuel system","bore","stroke","compression-ratio","horsepower", "peak-rpm","city-mpg","highway-mpg","price"]

Давайте заменим заголовки и перепроверим наш фрейм данных.

df.columns = headers
df.head(10)

Обработка данных

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

Как мы видим выше, во фрейме данных появилось несколько вопросительных знаков; это недостающие значения, которые могут помешать нашему дальнейшему анализу.

Итак, как работать с отсутствующими данными?

Шаги для работы с отсутствующими данными:

  1. Определить недостающие данные
  2. Работа с отсутствующими данными
  3. Правильный формат данных

Определение и обработка пропущенных значений

Конвертировать "?" в NaN

В наборе данных автомобиля отсутствующие данные помечаются вопросительным знаком «?». Заменяем «?» с NaN (Not a Number), маркером отсутствующих значений Python по умолчанию из соображений скорости и удобства вычислений.

df.replace('?', np.nan, inplace=True)
df.head(10)

Оценка отсутствующих данных

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

  1. .isnull()
  2. .notnull()

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

missing_data = df.isnull()
missing_data.head(5)

«Истина» означает, что значение является пропущенным значением, а «Ложь» означает, что значение не является пропущенным значением.

Подсчитайте пропущенные значения в каждом столбце

Используя цикл for в Python, мы можем быстро определить количество пропущенных значений в каждом столбце. Как упоминалось выше, «Истина» представляет отсутствующее значение, а «Ложь» означает, что значение присутствует в наборе данных. В теле цикла for метод .value_counts() подсчитывает количество «истинных» значений.

for column in missing_data.columns.values.tolist():
    print(column)
    print(missing_data[column].value_counts())
    print("")

Судя по приведенной выше сводке, каждый столбец содержит 205 строк данных, а семь столбцов содержат отсутствующие данные:

  1. "нормализованные потери": 41 отсутствующие данные
  2. "количество дверей": 2 пропущенных данных
  3. "скучно": 4 пропущенных данных
  4. "ход": 4 пропущенных данных
  5. "лошадиные силы": 2 пропущенных данных
  6. "пиковая скорость": 2 пропущенных данных
  7. "цена": 4 пропущенных данных

Работа с отсутствующими данными

Как быть с отсутствующими данными?

  1. Удалить данные — удалить всю строку или весь столбец.
  2. Заменить данные — заменить по среднему значению, заменить по частоте или заменить на основе других функций.

Целые столбцы следует удалять только в том случае, если большинство записей в столбце пусты. В нашем наборе данных ни один из столбцов не является достаточно пустым, чтобы его можно было полностью удалить. У нас есть некоторая свобода выбора метода замены данных; однако некоторые методы могут показаться более разумными, чем другие. Мы будем применять каждый метод ко многим различным столбцам:

Заменить на среднее:

  • "normalized-losss": 41 отсутствующие данные, замените их средним значением.
  • "ход": 4 пропущенных данных, замените их средним значением
  • "скучно": 4 пропущенных данных, замените их средним значением.
  • "лошадиные силы": 2 пропущенных данных, замените их средним значением

Заменить по частоте:

  • "количество дверей": 2 пропущенных данных, замените их на "четыре". Причина: 84% седанов четырехдверные. Поскольку чаще всего встречаются четыре двери, это, скорее всего, произойдет.

Удалить всю строку:

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

Рассчитать среднее значение для столбца "нормализованные потери"

avg_norm_loss = df["normalized-losses"].astype("flot").mean(axis=0)
print("Average of normalized-losses:", avg_norm_loss)

Выход: Average of normalized-losses: 122.0

Замените «NaN» средним значением в столбце «нормализованные потери».

df["normalized-losses"].replace(np.nan, avg_norm_loss, inplace=True)

Рассчитать среднее значение для столбца "скважина"

avg_bore = df["bore"].astype("float").mean(axis=0)
print("Average of bore:", avg_bore)

Выход: Average of bore: 3.3297512437810943

Замените «NaN» средним значением в столбце «отверстие».

df["bore"].replace(np.nan, avg_bore, inplace=True)

Замените столбец «ход» средним значением.

avg_stroke = df["stroke"].astype('float').mean(axis=0)
print("Average of Stroke", avg_stroke)
df["stroke"].replace(np.nan, avg_stroke, inplace=True)

Выход: Average of Stroke: 3.255422885572139

Рассчитать среднее значение для столбца "лошадиные силы"

avg_horsepower = df["horsepower"].astype("float").mean(axis=0)
print("Average horsepower:", avg_horsepower)

Выход: Average horsepower: 104.25615763546799

Замените «NaN» средним значением в столбце «лошадиные силы».

df["horsepower"].replace(np.nan, avg_horsepower, inplace=True)

Рассчитать среднее значение для столбца "пиковая скорость вращения"

avg_peakrpm = df["preak-rpm"].astype("float").mean(axis=0)
print("Average peak rpm:", avg_peakrpm)

Выход: Average peak rpm: 5125.369458128079

Замените «NaN» средним значением в столбце «пиковые обороты».

df["peak-rpm"].replace(np.nan, avg_peakrpm, inplace=True)

Чтобы увидеть, какие значения присутствуют в конкретном столбце, мы можем использовать метод .value_counts():

df["num-of-doors"].value_counts()

Мы видим, что четыре двери являются наиболее распространенным типом. Мы также можем использовать метод .idxmax() для автоматического вычисления наиболее распространенного типа:

df["num-of-doors"].value_counts().idmax()

Выход: 'four'

Процедура замены очень похожа на то, что мы видели ранее:

#replace the missing 'num-of-doors' values by the most frequent
df["num-of-doors"].replace(np.nan, "four", inplace=True)

Наконец, давайте отбросим все строки, в которых нет данных о ценах:

# simply drop whole row with NaN in "price" column
df.dropna(subset=["price"], axis=0, inplace=True)
# reset index, because we droped two rows
df.reset_index(drop=True, inplace=True)
df.head()

Теперь у нас есть набор данных без пропущенных значений.

Правильный формат данных

Мы почти у цели!

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

В Пандах мы используем:

  1. .dtype() для проверки типа данных
  2. .astype() для изменения типа данных

Давайте перечислим типы данных для каждого столбца

df.dtypes

Как мы видим выше, некоторые столбцы имеют неправильные типы данных. Числовые переменные должны иметь тип «float» или «int», а переменные со строками, такие как категории, должны иметь тип «object». Например, переменные «диаметр» и «ход» — это числовые значения, описывающие двигатели, поэтому мы должны ожидать, что они будут иметь тип «float» или «int»; однако они отображаются как тип «объект». Мы должны преобразовать типы данных в правильный формат для каждого столбца, используя метод astype().

Преобразование типов данных в правильный формат

df[["bore", "stroke"]] = df[["bore", "stroke"]].astype("float")
df[["normalized-losses"]] = df[["normalized-losses"]].astype("int")
df[["price"]] = df[["price"]].astype("float")
df[["peak-rpm"]] = df[["peak-rpm"]].astype("float")

Перечислим столбцы после преобразования

df.dtypes

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

Стандартизация данных

Данные обычно собираются из разных агентств в разных форматах. (Стандартизация данных — это также термин для определенного типа нормализации данных, когда мы вычитаем среднее значение и делим на стандартное отклонение.)

Что такое стандартизация?

Стандартизация — это процесс преобразования данных в общий формат, позволяющий исследователю проводить осмысленное сравнение.

Пример

Преобразование миль на галлон в л/100 км:

В нашем наборе данных столбцы расхода топлива «город-мили на галлон» и «шоссе-мили на галлон» представлены в милях на галлон (мили на галлон). Предположим, мы разрабатываем приложение в стране, которая принимает стандартный расход топлива в л/100 км.

Нам потребуется применить преобразование данных для преобразования миль на галлон в л/100 км.

Формула преобразования единиц измерения:

л/100 км = 235 миль на галлон

Мы можем выполнять многие математические операции прямо в Pandas.

df.head()

# Convert mpg to L/100km by mathematical operation (235 divided by mpg)
df['city-L/100km'] = 235/df["city-mpg"]
# check your transformed data
df.head()

Преобразуйте мили на галлон в л/100 км в столбце «шоссе-миль на галлон» и измените название столбца на «шоссе-л/100 км».

# transform mpg to L/100km by mathematical operation (235 divided by mpg)
df["highway-mpg"] = 235/df["highway-mpg"]
# rename column name from "highway-mpg" to "highway-L/100km"
df.rename(columns={'"highway-mpg"':'highway-L/100km'}, inplace=True)
# check your transformed data
df.head()

Нормализация данных

Зачем нормализация?

Нормализация — это процесс преобразования значений нескольких переменных в аналогичный диапазон. Типичные нормализации включают масштабирование переменной так, чтобы среднее значение переменной равнялось 0, масштабирование переменных, чтобы дисперсия равнялась 1, или масштабирование переменной, чтобы значения переменной находились в диапазоне от 0 до 1.

Пример

Чтобы продемонстрировать нормализацию, допустим, мы хотим масштабировать столбцы «длина», «ширина» и «высота».

Цель: хотелось бы нормализовать эти переменные, чтобы их значения находились в диапазоне от 0 до 1.

Подход: заменить исходное значение на (исходное значение)/(максимальное значение).

# replace (original value) by (original value)/(maximum value)
df['length'] = df['length']/df['length'].max()
df['width'] = df['width']/df['width'].max()

Нормализуйте столбец «высота».

df['height'] = df['height']/df['height'].max()
# show the scaled columns
df[["length","width","height"]].head()

Здесь мы видим, что мы нормализовали «длину», «ширину» и «высоту» в диапазоне [0,1].

Биннинг

Почему биннинг?

Биннинг — это процесс преобразования непрерывных числовых переменных в дискретные категориальные «бины» для группового анализа.

Пример:

В нашем наборе данных «лошадиная сила» — это переменная с действительным знаком в диапазоне от 48 до 288, имеющая 59 уникальных значений. Что, если нас интересует только разница в цене между автомобилями высокой, средней и малой мощности (3 типа)? Можем ли мы переставить их в три «корзины», чтобы упростить анализ?

Мы будем использовать метод pandas «cut», чтобы разделить столбец «лошадиные силы» на 3 ячейки.

Пример бинирования данных в Pandas

Скрыть данные в правильном формате:

df["horsepower"]=df["horsepower"].astype(int, copy=True)

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

%matplotlib inline
import matplotlib as plt
from matplotlib import pyplot
plt.pyplot.hist(df["horsepower"])
# set x/y labels and plot title
plt.pyplot.xlabel("horsepower")
plt.pyplot.ylabel("count")
plt.pyplot.title("horsepower bins")

Нам нужно 3 бина одинакового размера пропускной способности, поэтому мы используем функцию NumPy linspace (start_value, end_value, numers_generated).

Поскольку мы хотим включить минимальное значение лошадиных сил, мы хотим установить start_value = min(df["лошадиные силы"]).

Поскольку мы хотим включить максимальное значение лошадиных сил, мы хотим установить end_value = max(df["лошадиные силы"]).

Так как мы строим 3 бина одинаковой длины, разделителей должно быть 4, значит, number_generated = 4.

Мы строим массив ячеек с минимальным значением до максимального значения, используя пропускную способность, рассчитанную выше. Значения будут определять, когда заканчивается один бин и начинается другой.

bins = np.linspace(min(df["horsepower"]), max(df["horsepower"]), 4)
bins

Выход: array([48. , 119.33333333, 190.66666667, 262. ])

Задаем имена групп:

group_names = [“Low”, “Medium”, “High”]

Мы применяем функцию «вырезать», чтобы определить, чему принадлежит каждое значение df["horsepower"].

df['horsepower-binned'] = pd.cut(df['horsepower'], bins, labels=group_names, include_lowest=True )
df[['horsepower','horsepower-binned']].head(20)

Посмотрим количество автомобилей в каждой корзине:

df["horsepower-binned"].value_counts()

Давайте построим распределение каждого бина:

%matplotlib inline
import matplotlib as plt
from matplotlib import pyplot
pyplot.bar(group_names, df["horsepower-binned"].value_counts())
# set x/y labels and plot title
plt.pyplot.xlabel("horsepower")
plt.pyplot.ylabel("count")
plt.pyplot.title("horsepower bins")

Внимательно посмотрите на фрейм данных выше. Вы обнаружите, что в последнем столбце представлены ячейки для «лошадиных сил» на основе 3 категорий («Низкая», «Средняя» и «Высокая»).

Мы успешно сузили интервалы с 59 до 3!

Индикаторная переменная (или фиктивная переменная)

Что такое индикаторная переменная?

Индикаторная переменная (или фиктивная переменная) — это числовая переменная, используемая для маркировки категорий. Их называют «пустышками», потому что сами числа не имеют внутреннего значения.

Почему мы используем индикаторные переменные?

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

Пример

Мы видим, что столбец «тип топлива» имеет два уникальных значения «газ» и «дизель». Регрессоры не понимают слов, только числа. Чтобы использовать этот атрибут в регрессионном анализе, мы конвертируем «тип топлива» в индикаторные переменные.

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

df.columns

Получите переменные индикатора и назначьте их фрейму данных «dummy_variable_1»:

dummy_variable_1 = pd.get_dummies(df["fuel-type"])
dummy_variable_1.head()

Измените имя столбца для ясности:

dummy_variable_1.rename(columns={'gas':'fuel-type-gas', 'diesel':'fuel-type-diesel'}, inplace=True)
dummy_variable_1.head()

Во фрейме данных столбец «тип топлива» теперь имеет значения для «газ» и «дизель» как 0 и 1.

# merge data frame "df" and "dummy_variable_1"
df = pd.concat([df, dummy_variable_1], axis=1)
# drop original column "fuel-type" from "df"
df.drop("fuel-type", axis = 1, inplace=True)
df.head()

Последние два столбца теперь представляют собой индикаторную переменную, представляющую переменную типа топлива. Теперь они все 0 и 1.

Как и раньше, давайте создадим индикаторную переменную для столбца «стремление».

# get indicator variables of aspiration and assign it to data frame "dummy_variale_2"
dummy_variable_2 = pd.get_dummies(df["aspiration"])
# change column names for clarity
dummy_variable_2.rename(colums={"std":"aspiration-std", "turbo":"aspiration-turbo"}, inplace=True)
# show first 5 instances of data frame "dummy_variable_1"
dummy_variable_2.head()

Давайте объединим новый фрейм данных с исходным фреймом данных, а затем удалим столбец «стремление».

# merge the new dataframe to the original dataframe
df = pd.concat([df, dummy_variable_2], axis=1)
# drop original column "aspiration" from "df"
df.drop("aspiration", axis=1, inplace=True)
# Display new data frame
df.head()

Сохранить набор данных

Соответственно, Pandas позволяет нам сохранять набор данных в CSV. Используя метод dataframe.to_csv(), мы можем добавить путь и имя файла вместе с кавычками в скобках.

Например, если вы хотите сохранить кадр данных df как автомобиль.csv на свой локальный компьютер, вы можете использовать приведенный ниже синтаксис, где index = False означает, что имена строк не будут записаны.

df.to_csv("clean_df.csv", index=False)

Краткое содержание

  1. Выявление и обработка отсутствующих значений.Отбрасывайте строки с неполной информацией и заполняйте отсутствующие данные, используя средние значения.
  2. Понимание форматирования данных. Упорядочивайте объекты в наборе данных и делайте их значимыми для анализа данных.
  3. Применить нормализацию к набору данных. Понимая актуальность использования масштабирования функций в наших данных и то, как нормализация и стандартизация по-разному влияют на анализ ваших данных.

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

Пожалуйста, не стесняйтесь ссылаться также на Записную книжку.