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

Условия и циклы

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

🔍 Ветвление — ситуация, когда выполнение или невыполнение инструкции зависит от некоторого условия.

🔍 Цикл — многократно исполняемая инструкция.

🔍 Инструкция — это набор методов или функций, исполняемых последовательно.

Примеры будут чуть ниже, сейчас важно отметить ещё несколько нюансов. Ветвление должно обязательно содержать условие и инструкцию, которую необходимо выполнить, если условие соблюдается. Если условие не соблюдается, то может (но не обязательно!) быть инструкция на этот счёт. Если её нет, то интерпретатор просто переходит к следующей инструкции.

Простейший пример ветвления — это условная конструкция.

>>> i = 12
>>> if i % 2 == 0:
>>>     print(i, ' - чётное число')
>>> else:
>>>     print(i, ' - нечётное число')
12 - чётное число

Здесь мы создаём переменную i, которой присваиваем в качестве значения любое целое число. Дальше мы проверяем, является ли это число кратным двум или нет. Для этого мы вычисляем остаток от деления на два и сравниваем его с нулём. Если они совпадают, то мы выводим число и пояснение, что это чётное число. Иначе мы выводим число и пояснение, что это нечётное число.

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

Теперь поговорим о циклах. Цикл состоит из двух частей:

  • условия – оно проверяется на каждом шаге цикла;
  • инструкций — они выполняются на каждом шаге цикла, если соблюдается условие.

Есть два вида циклов: while и for. Сперва поговорим про while. Для начала посмотрите пример:

>>> i = 0
>>> while i < 5:
>>>     print(i)
>>>     i += 1
0
1
2
3
4

Здесь условие заключается в том, что переменная i должна быть меньше 5. Переменная i — это счётчик. Его значение определяет, сколько раз уже выполнился цикл.

Соответственно, инструкция — вывести в консоль текущее значение переменной i и увеличить счётчик на единицу. Инструкция будет выполняться до тех пор, пока i не будет равна 4. Как только i станет равна 5, выражение i < 5 перестанет быть истинным, и цикл прервётся.

Тут важно отметить, что вместо команды print может быть всё что угодно. Но увеличение счётчика важно сохранить — иначе потеряется условие выхода из цикла, и он станет бесконечным.

Последнее, о чём тут важно сказать, — на практике при анализе данных цикл while применяется редко.

Теперь поговорим о цикле for. Он нужен, если мы хотим пройтись по списку (или массиву, или словарю — одним словом, любой последовательности) и что-то сделать с каждым элементом.

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

>>> list_with_elements = [1, 2, 3, 4]
>>> for i in list_with_elements:
>>>     print(i ** 2)
1
4
9
16

Давайте начнём с переменной i (это самая трудная часть). Эта переменная существует только внутри цикла и создаётся повторно на каждом этапе.

Если разбить цикл на шаги, то он будет таким:

  1. проверяем, остались ли в списке элементы;
  2. присваиваем переменной i значение следующего по порядку элемента списка (на первом шаге это нулевой элемент);
  3. выполняем инструкцию — возводим i в квадрат;
  4. возвращаемся на первый шаг.

Также мы можем использовать функцию range(), которая позволяет генерировать последовательности цифр. Их тоже можно использовать в цикле for. Мы не будем подробно останавливаться на этой функции, но вы можете почитать о ней подробнее, например, тут.

Вы можете поэкспериментировать с этим и другими примерами на сайте pythontutor.com, который позволяет визуализировать ветвления.

И последнее, что стоит запомнить:

  • в случае while мы находимся внутри цикла до тех пор, пока соблюдается условие;
  • в случае for — до тех пор, пока в списке остаются элементы.

Категориальные переменные в Python

Напомним, что категориальные переменные — это те переменные, которые выражены ограниченным диапазоном значений. Например, группа крови или семейное положение. Хотя часто для категориальных переменных мы используем строки, датафрейм в Pandas содержит реализацию категориальных переменных. Использование категориальных переменных позволяет:

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

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

Представим, что мы хотим создать из строки категориальную переменную «семейный статус». Мы можем захотеть сэкономить память или визуализировать её. Здесь мы сначала создаём набор из нескольких значений, затем присваиваем им категориальный тип данных.

>>> status = pd.Series([“single”, “married”, “divorced”, “single”, “divorced”], dtype = “category”)
>>> print(status)
0      single
1     married
2    divorced
3      single
4    divorced
dtype: category
Categories (3, object): ['divorced', 'married', 'single']

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

Хи-квадрат в Python

Чтобы рассчитать хи-квадрат в Python, нам необходимо соотнести ожидаемые и наблюдаемые значения.

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

Голова болит

Голова не болит

Всего

Делают гимнастику

20

30

50

Не делают гимнастику

50

25

75

Всего

70

55

125

И таблица ожидаемых значений:

Голова болит

Голова не болит

Всего

Делают гимнастику

28

22

50

Не делают гимнастику

42

33

75

Всего

70

55

125

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

>>> import scipy.stats as stats
>>> stats.chisquare([20, 30, 50, 25], f_exp=[28, 22, 42, 33])
Power_divergenceResult(statistic=8.658008658008658, pvalue=0.0342009767864908)

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

Типы данных и их изменение в Python

Представим себе простую задачку. У нас есть список детей, рождённых за последние сутки, с указанием их веса в граммах. Нам необходимо распределить их на тех, кто родился с дефицитом веса, и тех, кто родился с нормальным. Для новорожденных детей нижняя граница нормального веса составляет 2700 г.

Изначально переменная веса – целочисленная (integer), теперь нам нужно перевести её в категориальную («нормальный вес» / «низкий вес»)

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

>>> df = df.assign(weight_dummy=['normal' if i > 2700 else 'low' for i in df['weight']])

В скобках альтернативный способ записи цикла. Он используется, когда результат выполнения цикла — это новый список. Тут для каждого значения в колонке weight мы добавляем в список normal, если оно больше, чем 2700. Если нет, то low. Дальше мы сохраняем эти значения как колонку weight_dummy. В итоге у нас есть категориальная переменная, с которой можно работать дальше.

Pandas dtype

Python type

Что это такое

object

str/mixed

Текстовые данные / числовые + нечисловые данные (18 кошек)

int64

int

Целые числа (1, 2, 115...)

float64

float

Число с плавающей точкой (12.15)

bool

bool

Значения true/false (истина/ложь)

datetime64

-

Дата и время (20220308)

category

-

Категориальные переменные (низкий доход, средний доход, высокий доход)

Еще есть несколько особенных типов переменных. Тип None — это переменная, которой пока не присвоено значение. Мы создаём её на будущее, чтобы позднее присвоить значение (тогда у нового значения уже будет определённый тип переменной) или для того, чтобы обозначить, что тут ничего нет. Рассмотрим на примере.

Мы создали переменную a, у которой пока нет значения, и присвоили ей тип None:

>>> a = None
>>> print(type(a))
<class 'NoneType'>

Теперь мы присвоили переменной a значение 252. Это число, поэтому переменная a становится числовой.

>>> a = 252
>>> print(type(a))
<class 'int'>

dtypes — это функция в pandas, которая определяет тип данных в каждой колонке.

>>> df = pd.DataFrame({'float': [7.3],
'int': [7],
'datetime': [pd.Timestamp('20220308')],
'string': ['pizza']})
>>> df.dtypes
float              float64
int                  int64
datetime    datetime64[ns]
string              object
dtype: object

astype() — это функция в pandas, которая меняет тип данных.

Создадим базу данных новорождённых детей: их имена, вес в граммах и гендер.

>>> import pandas as pd
>>> children = pd.DataFrame({"name":["Roman","Anna","Dmitry"],
"weight":[3400,3500,2900],
"gender":["male","female","male"]
}, dtype = "object")
>>> print(children)
     name weight  gender
0   Roman   3400    male
1    Anna   3500  female
2  Dmitry   2900    male

Определим тип данных с помощью команды dtypes, о которой мы говорили ранее.

>>> children.dtypes
name      object
weight    object
gender    object
dtype: object

Поскольку на этапе создания базы данных мы присвоили всем нашим переменным тип object, команда dtype определяет его именно так. Теперь выберем одну из переменных — гендер (gender) — и попробуем изменить её тип.

Поскольку гендер часто записан как категориальная переменная, изменим его именно так:

>>> children['gender'].astype('category')
0      male
1    female
2      male
Name: gender, dtype: category
Categories (2, object): ['female', 'male']

Теперь детям присвоена одна из двух категорий гендера — мужская или женская.

Дальше мы можем перевести категориальную переменную в числовую (что бывает полезно для некоторых расчётов).

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

children['gender'].replace(['male','female'],
[0,1],inplace = True)

А затем изменить тип переменной на числовую:

>>> children.gender.astype('int32')
0    0
1    1
2    0
Name: gender, dtype: int32

Изменение типов float — integer

Ранее у новорождённых детей, о которых мы говорили, вес был указан в граммах. Теперь поработаем с изменённой базой данных, в которой вес указан в килограммах и переменная относится к типу float.

>>> import pandas as pd
>>> children = pd.DataFrame({"name":["Roman","Anna","Dmitry"]
,"weight":[3.4,3.5,2.9]
,"gender":["male","female","male"]
})
>>> print (children)
>>> print (children.dtypes)
name  weight  gender
0   Roman     3.4    male
1    Anna     3.5  female
2  Dmitry     2.9    male
name       object
weight    float64
gender     object
dtype: object

Теперь переведём float обратно вinteger, так чтобы знаки после точки исчезли:

>>> children['weight'] = children['weight'].astype(int)
>>> print (children)
>>> print (children.dtypes)
name  weight  gender
0   Roman       3    male
1    Anna       3  female
2  Dmitry       2    male
name      object
weight     int64
gender    object
dtype: object

В этой главе мы поговорили о функциях условий и циклов, которые добавляют вариативность скриптам. Попробовали поработать с категориальными переменными и выполнили тест «Хи-квадрат». Наконец, разобрались с тем, как изменять тип данных в Python.

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

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

А в следующем разделе мы поговорим о том, как сделать простую и понятную визуализацию данных с помощью графиков и диаграмм. Эти знания помогут вывести ваши отчёты и презентации на новый уровень!

Отмечайте параграфы как прочитанные чтобы видеть свой прогресс обучения

Вступайте в сообщество хендбука

Здесь можно найти единомышленников, экспертов и просто интересных собеседников. А ещё — получить помощь или поделиться знаниями.
Вступить
Сообщить об ошибке
Предыдущий параграф4.2. Категориальные переменные и их анализ
Следующий параграф5.1. Использование визуализации данных в исследованиях