Прежде чем вы начнете с «забавных» и «захватывающих» алгоритмов и методов, вот первые шаги к успеху в вашем проекте данных.

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

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

Изучите и очистите свои данные

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

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

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

На этом этапе я думаю, что стоит задуматься над вопросом:

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

Первое, что я бы порекомендовал после импорта данных во фрейм данных, - это просто проверить, соответствуют ли данные, которые у вас есть, ожидаемым. Для этого я проверяю первые пять строк, используя df.head (где df = ваш DataFrame).

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

Однако то, что мы видим, может не совпадать с тем, что видит компьютер, поэтому важно проверить, какие типы присутствуют: df.dtypes сделает это за вас. Для вышеуказанного DataFrame мы получаем следующий результат:

Как вы можете видеть здесь, в выходных данных мне сообщаются разные имена столбцов с типом данных, которые в них находятся. Что-то, чего не делает только печать DataFrame. Из таблицы не было способа узнать, являются ли значения строками, числами с плавающей запятой или другими. Это важная информация даже для первоначального создания простых графиков - вы не можете построить график рассеяния со строками! - но когда вы продвинетесь дальше, вы можете использовать регрессию случайного леса, которая требует числовых данных, а не строк.

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

Как правило, если у нас есть элементы, которые мы, люди, видим как числа или даты в DataFrame, мы хотим, чтобы компьютер тоже их видел. Здесь я бы предложил преобразовать столбец «Дата рождения» в даты, а столбец «Возраст на момент смерти» в целые числа, используя следующий код (где pd - это библиотека pandas):

df['Age at Death'] = df['Age at Death'].astype(int)
df['Date of Birth'] = pd.to_datetime(df['Date of Birth'])

Когда я снова показываю DataFrame, он выглядит так:

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

Однако, если мы посмотрим на типы данных, которые находятся в каждом столбце, вы увидите, что здесь показаны два преобразованных нами:

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

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

В приведенном выше примере мы видим, что в DataFrame отсутствует дата рождения Эрнеста Резерфорда - это ясно видно с NaT или Not a Time (пример нулевого значения времени). Однако, не глядя внимательно в столбец «Возраст смерти», вы можете пропустить, что Мари Склодовской Кюри нулевой возраст. При большом DataFrame оба этих примера могут быть пропущены, поэтому важно кратко получить информацию о числовых аспектах DataFrame, чтобы вы могли на нее взглянуть, для этого я использую df.describe():

Поскольку единственный числовой столбец, который у нас есть, - это «Возраст на момент смерти», ожидается, что мы увидим один столбец в выходных данных. Если бы у вас был DataFrame с более чем одним числовым столбцом, каждый из них был бы отображен аналогично. Мы ясно видим, что минимальное значение равно нулю, и мы можем использовать наш человеческий интеллект, чтобы понять, что здесь что-то не так. В этом случае может случиться так, что где бы ни были получены ваши данные, значение заменено на ноль, чтобы показать, что для нас не было данных. Однако в Python нам нужно отображать это как NaN или null, поэтому в этой ячейке действительно ничего нет. Здесь вы можете использовать df.replace(0, np.NaN) (где np - библиотека numpy), чтобы дать следующее:

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

Чтобы проверить нулевые значения в DataFrame, вы также можете использовать df.isna().count(), который дает следующий результат:

Вышеупомянутый метод - это быстрый и четкий способ определить, сколько данных отсутствует в вашем DataFrame. Опять же, для этого примера это может показаться немного излишним, но когда вам придется иметь дело с сотнями столбцов и тысячами строк, вы оцените этот метод (возможно, даже раньше!)

Обычно, когда у меня есть числовые данные, я люблю строить их после того, как закончу первоначальную очистку. Я делаю это в рамках своего исследования: могу ли я увидеть очевидную тенденцию? Есть ли явные аномалии или ошибки, которые могут исказить мои данные? Я считаю, что это помогает мне видеть то, что есть на самом деле, а не то, что я вижу в фрагментах DataFrame.

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

fig, ax = plt.subplots()
x = df['Date of Birth']
y = df['Age at Death']
plt.plot(x, y, 'bo')
fig.suptitle('Year of Birth vs Age at Death', fontsize=20)
xlabel = 'Year of Birth'
ylabel = 'Age at Death'
ax.set_xlabel(xlabel, fontsize=10)
ax.set_ylabel(ylabel, fontsize='medium')

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

Однако Python немного запутался, поскольку он показывает точку данных для Эрнеста Резерфорда примерно в 1680 году. Кажется, что из-за присутствия NaT вместо его даты рождения Python выбрал самую раннюю возможную дату и построил возраст в точке данных о смерти. Это то, чего стоит остерегаться! С небольшими дополнительными манипуляциями вы можете убедиться, что он также исключен, выбрав значения x и значения y вашего графика для построения из строк DataFrame, где нет нулевых значений, с небольшим добавлением df.dropna():

fig, ax = plt.subplots()
df2 = df.dropna()
x = df2['Date of Birth']
y = df2['Age at Death']
plt.plot(x, y, 'bo')
fig.suptitle('Year of Birth vs Age at Death', fontsize=20)
xlabel = 'Year of Birth'
ylabel = 'Age at Death'
ax.set_xlabel(xlabel, fontsize=10)
ax.set_ylabel(ylabel, fontsize='medium')

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

Последние слова

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

Естественно, что с более сложным набором данных возможности становятся все более захватывающими.

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