У вас есть данные которые надо превратить в аккуратную табличку, Pandas вам поможет ) Pandas — программная библиотека на языке Python для обработки и анализа данных. Работа с данными строится поверх библиотеки NumPy, являющейся инструментом более низкого уровня. Вообщем если вы хотите ваши хаотичные данные загнать в красивую табличку, где уже намного легче обрабатывать и анализировать данные, поехали.
У нас есть набор данных, который нужно превратить в таблицу. Это делается вызовом конструктора DataFrame() Конструктор принимает два аргумента – список данных и названия столбцов, которые должны быть в таблице. Попробуем :
import pandas as pd
data = [['yakov_segidenko', 'yakov_segidenko@mail.ru', '1010vbh'],
['novokuzmenu', 'novokuzmenu@mail.ru', '9068989m'],
['zhele.anastasiya', 'zhele.anastasiya@mail.ru', 'drakosha']
]
colums = ['login', 'mail', 'pass']
tables = pd.DataFrame(data = data , columns = colums)
print(tables)

Вот мы получили аккуратную таблицу с 3-мя колонками и 3-мя рядами (с 0 по 2 индекс). Конечно мы руками не будем забивать все данные. Давайте загрузим из CSV файла: я подготовил небольшую базу для примера, на которой мы будем тренироваться. Качаем .
df = pd.read_csv('mail.csv' ,error_bad_lines=False)
# error_bad_lines=False - база немного битая , пропускаем строки с ошибками.
CSV (от англ. Comma-Separated Values — значения, разделённые запятыми) — текстовый формат, предназначенный для представления табличных данных. Строка таблицы соответствует строке текста, которая содержит одно или несколько полей, разделенных запятыми.
Информация о базе.
Давайте ознакомимся с данными с помощью двух методов : head() и tail() . head(по умолчанию 5) — вернет строки набора данные с начала таблички, tail() — соответственно с хвоста.
print(df.head())
print(df.tail())

У DataFrame есть неотъемлемые свойства, значения которых можно запросить. Атрибут columns содержит информацию о названиях столбцов в наборе данных. Для просмотра типа данных каждого столбца лучше всего использовать атрибут dtypes. object соответствует типу srt. О размерах таблицы с данными сообщает её атрибут shape.
print(df.columns)
print()
print(df.dtypes)
print()
print(df.shape)

Всю информацию, которую предоставляют разные атрибуты DataFrame, можно получить вызовом одного-единственного метода info().
print(df.info())

Работа с данными или индексация.
К каждой ячейке с данными в DataFrame можно обратиться по её индексу и названию столбца. Мы можем получать различные срезы данных в зависимости от того, какой запрос к DataFrame мы сформулируем.
Атрибут loc[строка, столбец]
даёт доступ к элементу по строке и столбцу.
- Одна ячейка —
.loc[7, 'название столбца']
- Один столбец —
.loc[:, 'название столбца']
- Несколько столбцов —
.loc[:, ['название столбца', 'название столбца']]
- Несколько столбцов подряд (срез) —
.loc[:, 'login': 'pass']
- Одна строка —
.loc[1]
- Все строки, начиная с заданной —
.loc[1:]
- Все строки до заданной —
.loc[:3]
- Несколько строк подряд (срез) —
.loc[2:5]
Но это не самое интересное, мы можем использовать логическую индексацию. Давайте сделаем выборку все данных где пароль задан 12345 :
tmp = df.loc[df.loc[:,'pass'] == '12345'][:]
print(tmp)

[: , 'pass'] == '12345' ]
— логическое условие которое проверяется для каждого элемента столбца 'pass'
. [ : ]
— какой столбец выбираем.
Так же мы можем посчитать количество данных. В Pandas для этого есть метод count()
:
tmp = df.loc[df.loc[:,'pass'] == '12345']
print(tmp.count())
login 4 mail 4 pass 4 dtype: int64
Для примера посчитаем долю паролей «12345» в базе данных :
total_pass = df.loc[:, 'Password']
sim_pass = df.loc[df.loc[:, 'Password'] == '12345']['Password'].count()
x = sim_pass / (total_pass.loc[:].count())
print('Пароль "12345" используется только в {:.3%} случаях'.format(x))
>>> Пароль "12345" используется только в 0.027% случаях.
Очистка данных.
Конечно данные не идеальны. Где то пропущены значения, возможно есть дубликаты и т.д. Pandos конечно нам позволяет очистить данные от мусора.
Для начало поменяем название столбцов, воспользуемся методом set_axis()
. Он принимает три аргумента:
- список с новыми названиями столбцов;
- axis — ось, которой новые названия присваиваются: ‘index’, если они даются строкам, и ‘columns’, если это список новых названий столбцов;
- inplace — принимает значения True либо False. В первом случае метод
set_axis()
перестраивает структуру данных так, что она замещает прежнюю в переменной с тем же именем.
new = ['Login', 'Email', 'Password']
df.set_axis(new, axis = 'columns', inplace = True)
Так же в данных бывает что и нет данных ) В нашей таблице есть ячейки без данных .Замены пропущенных значений в DataFrame бывают трёх видов:
- Ожидаемые: None или NaN. None (англ. none, «ничто») — это эквивалент null в других языках программирования: особое значение, указывающее, что в этой ячейке таблицы никакого значения нет. None относится к NoneType .
- Странные: плейсхолдеры (тексты-заполнители) какого-нибудь общепринятого стандарта, иногда неизвестного вам, но которого придерживаются составители. Чаще всего это n/a, na, NA (от англ. no answer, «нет ответа»), и N.N.либо NN (от лат. Nomen nescio, «не знаю имени»).
- Неожиданные: например, разработчики решили, что пустые значения в таблице будут заполняться знаками вопроса или нулями. В лучшем случае этот факт укажут в документации, в худшем – придётся просматривать данные самостоятельно. Если какой-нибудь спецсимвол или число встречаются часто, и этому нет внятного объяснения, то высока вероятность, что так передаются пропущенные значения.
Для поиска первых двух типов в Pandas есть два метода .isnull() и .isna()
. Если значение элемента не существует, .isnull() и .inna()
возвращает True, а иначе — False. Суммируют эти True вызовом метода sum()
который в этом случае возвращает общее число элементов без определённых значений.
print('.isna()')
print(df.isna().sum())
print('.isnull()')
print(df.isnull().sum())

Как мы видим у нас есть пропущенные значения в столбце Login и Password. Давайте пропущенные значения в столбце Login заполним нулями . Для этого будем использовать метод .fillna(чем заполнить)
print(df.loc[8640])
df['Login'] = df['Login'].fillna(0)
print()
print(df.loc[8640])

А строки с пропущенными данными в Password удалим методом .dropna()
print(df.loc[8150:8160])
df.dropna(subset = ['Password' ], inplace= True)
print()
print(df.loc[8150:8160])

________________________________________________________________________________________________
Заметьте , индексирование таблицы у нас нарушилась : после 8152 идет сразу 8154 . Исправим это методом
.reset_index( drop=True )
.
Теперь перейдем к дубликатам. Для поиска дубликатов есть метод .duplicated()
. Он возвращает Series со значением True при наличии дубликатов, и False, когда их нет.
print('Всего дубликатов',df.duplicated().sum())
Всего дубликатов 3641
Login Email Password
1740 zhele.anastasiya zhele.anastasiya@mail.ru drakosha
14962 zhele.anastasiya zhele.anastasiya@mail.ru drakosha
Для удаления дубликатов из данных используем метод .drop_duplicates()
df = df.drop_duplicates().reset_index(drop=True)
Для просмотра всех уникальных значений в столбце используется метод .unique()
Для замены определенных значений можно воспользоваться методом replace()
, где первый аргумент — текущее значение, а второй — новое, нужное.
df['Солб'] = df['Солб'].replace('12345', '123457')
Анализ данных.
Для анализа данных мы возьмем базу найденных экзопланет в формате CSV , качаем.
- name: название экзопланеты;
- mass: масса в массах планеты Юпитер;
- radius: радиус, пересчитанный в радиусах Земли;
- discovered: год открытия экзопланеты.
- star_mass : масса в массах Солнца.
Анализ данных начинают с разделения их на группы по какому-нибудь признаку. Эта операция называется группировка данных. Группировка оправданна, если данные чётко делятся по значимому признаку, а полученные группы близки к теме задачи.
В Рandas для группировки данных есть метод .groupby()
. Он принимает как аргумент название столбца, по которому нужно группировать. В случае с делением экзопланет по годам открытия:
import pandas as pd
df = pd.read_csv('exoplanet.eu_catalog.csv' ,error_bad_lines=False)
print(df.groupby('discovered').count())
Применение метода .groupby()
к объекту типа DataFrame приводит к созданию объекта особого типа — DataFrameGroupBy. Это сгруппированные данные. Если применить к ним какой-нибудь метод Pandas, они станут новой структурой данных типа DataFrame или Series.

Если нужно сравнить по одному показателю, метод применяют к DataFrameGroupBy с указанием на один столбец. Например радиус :
radius = df.groupby('discovered')['radius'].count()
print(radius)
Давайте сделаем выборку по планетам радиус которых почти равен земному и отсортируем по убыванию. Для сортировки значений в Pandas есть метод .sort_values( )
- ‘имя столбца’ — имя столбца, по которому нужно сортировать;
- ascending: по умолчанию True. Для сортировки по убыванию установите значение False.
exo = df[(df['radius'] <= 1.1) & (df['radius'] >= 0.9)].sort_values('radius')
print(exo)
Oписательная статистика — четыре основных метода максимум, минимум, медиана и среднее
grup = df.groupby('discovered')
# Максимум
print(grup['radius'].max())
# Минимум
print(grup['radius'].min())
В статистике медиана делит выборку пополам: в одной половине значения меньше медианного, в другой больше. Логично, что для определения медианы список обязательно должен быть отсортирован — либо по возрастанию, либо по убыванию.
df.sort_values('radius')
#Медиан
print(grup['radius'].median())
#Сред
print(grup['radius'].mean())

Спасибо 🙂
Прикольно, что автор делает подробно разбор в IDE PyCharm, хотя многие также рассматривают jupyter notebook.
Спасибо за ваш отзыв. IDE PyCharm рулит )))
Не пробовали jupyter notebook?
Там просто удобно следующее: печатать код, запускать его без компиляции заново 🙂
Начинал сам с PyCharm, но сломали меня юпитером 🙂
Да, я видел его. Но PyCharm приучает к PEP 8. И когда пишешь много кода IDE все равно удобен. jupyter notebook вроде же не полноценное IDE. Отлично подходит для обучающих заданий и т.д.