Пару недель назад вышло обновление для ОС Windows 10 под кодовым названием Creators Update. Помимо ежегодных плюшек в пользовательском интерфейсе и улучшений в производительности, с этим обновлением также "прилетел" апдейт для подсистемы Linux внутри Windows 10. Год назад я уже писал о том как установить Ubuntu в Windows 10. На момент прошлой заметки, в Windows 10 была возможность включить полноценный дистрибутив Linux — Ubuntu версии 14.04 LTS. Всё бы хорошо, но 14.04 вышла 3 года назад, пора бы идти в ногу со временем и обновиться до более свежей версии (учитывая, что в 14.04 стоит Python аж версии 2.7.6). С приходом подсистемы Linux, таким разработчикам как я (любителям Windows) можно забыть про использование инструментов вроде Vagrant для унификации систем развертывания и разработки.
Итак, как же обновить Linux? Если у вас ещё не установлена подсистема Linux, но при этом обновление Creators Update уже стоит, то следуйте инструкциям из моей прошлогодней статьи, с одним лишь замечанием, что теперь Программы и компоненты спрятаны в раздел Приложения и возможности.
pandas это высокоуровневая Python библиотека для анализа данных. Почему я её называю высокоуровневой, потому что построена она поверх более низкоуровневой библиотеки NumPy (написана на Си), что является большим плюсом в производительности. В экосистеме Python, pandas является наиболее продвинутой и быстроразвивающейся библиотекой для обработки и анализа данных. В своей работе мне приходится пользоваться ею практически каждый день, поэтому я пишу эту краткую заметку для того, чтобы в будущем ссылаться к ней, если вдруг что-то забуду. Также надеюсь, что читателям блога заметка поможет в решении их собственных задач с помощью pandas, и послужит небольшим введением в возможности этой библиотеки.
DataFrame и Series
Чтобы эффективно работать с pandas, необходимо освоить самые главные структуры данных библиотеки: DataFrame и Series. Без понимания что они из себя представляют, невозможно в дальнейшем проводить качественный анализ.
Series
Структура/объект Series представляет из себя объект, похожий на одномерный массив (питоновский список, например), но отличительной его чертой является наличие ассоциированных меток, т.н. индексов, вдоль каждого элемента из списка. Такая особенность превращает его в ассоциативный массив или словарь в Python.
В строковом представлении объекта Series, индекс находится слева, а сам элемент справа. Если индекс явно не задан, то pandas автоматически создаёт RangeIndex от 0 до N-1, где N общее количество элементов. Также стоит обратить, что у Series есть тип хранимых элементов, в нашем случае это int64, т.к. мы передали целочисленные значения.
У объекта Series есть атрибуты через которые можно получить список элементов и индексы, это values и index соответственно.
Делать выборку по нескольким индексам и осуществлять групповое присваивание:
>>> my_series2[['a', 'b', 'f']]
a 5
b 6
f 10
dtype: int64
>>> my_series2[['a', 'b', 'f']] = 0
>>> my_series2
a 0
b 0
c 7
d 8
e 9
f 0
dtype: int64
Фильтровать Series как душе заблагорассудится, а также применять математические операции и многое другое:
>>> my_series2[my_series2 > 0]
c 7
d 8
e 9
dtype: int64
>>> my_series2[my_series2 > 0] * 2
c 14
d 16
e 18
dtype: int64
Если Series напоминает нам словарь, где ключом является индекс, а значением сам элемент, то можно сделать так:
>>> my_series3 = pd.Series({'a': 5, 'b': 6, 'c': 7, 'd': 8})
>>> my_series3
a 5
b 6
c 7
d 8
dtype: int64
>>> 'd' in my_series3
True
У объекта Series и его индекса есть атрибут name, задающий имя объекту и индексу соответственно.
>>> my_series3.name = 'numbers'
>>> my_series3.index.name = 'letters'
>>> my_series3
letters
a 5
b 6
c 7
d 8
Name: numbers, dtype: int64
Индекс можно поменять "на лету", присвоив список атрибуту index объекта Series
>>> my_series3.index = ['A', 'B', 'C', 'D']
>>> my_series3
A 5
B 6
C 7
D 8
Name: numbers, dtype: int64
Имейте в виду, что список с индексами по длине должен совпадать с количеством элементов в Series.
DataFrame
Объект DataFrame лучше всего представлять себе в виде обычной таблицы и это правильно, ведь DataFrame является табличной структурой данных. В любой таблице всегда присутствуют строки и столбцы. Столбцами в объекте DataFrame выступают объекты Series, строки которых являются их непосредственными элементами.
DataFrame проще всего сконструировать на примере питоновского словаря:
Объект DataFrame имеет 2 индекса: по строкам и по столбцам. Если индекс по строкам явно не задан (например, колонка по которой нужно их строить), то pandas задаёт целочисленный индекс RangeIndex от 0 до N-1, где N это количество строк в таблице.
Как можно заметить, .loc в квадратных скобках принимает 2 аргумента: интересующий индекс, в том числе поддерживается слайсинг и колонки.
>>> df.loc['KZ':'BY', :]
country population square
Country Code
KZ Kazakhstan 17.04 2724902
RU Russia 143.50 17125191
BY Belarus 9.50 207600
Фильтровать DataFrame с помощью т.н. булевых массивов:
>>> df[df.population > 10][['country', 'square']]
country square
Country Code
KZ Kazakhstan 2724902
RU Russia 17125191
UA Ukraine 603628
Кстати, к столбцам можно обращаться, используя атрибут или нотацию словарей Python, т.е. df.population и df['population'] это одно и то же.
Сбросить индексы можно вот так:
>>> df.reset_index()
Country Code country population square
0 KZ Kazakhstan 17.04 2724902
1 RU Russia 143.50 17125191
2 BY Belarus 9.50 207600
3 UA Ukraine 45.50 603628
pandas при операциях над DataFrame, возвращает новый объект DataFrame.
Добавим новый столбец, в котором население (в миллионах) поделим на площадь страны, получив тем самым плотность:
>>> df['density'] = df['population'] / df['square'] * 1000000
>>> df
country population square density
Country Code
KZ Kazakhstan 17.04 2724902 6.253436
RU Russia 143.50 17125191 8.379469
BY Belarus 9.50 207600 45.761079
UA Ukraine 45.50 603628 75.377550
Не нравится новый столбец? Не проблема, удалим его:
>>> df.drop(['density'], axis='columns')
country population square
Country Code
KZ Kazakhstan 17.04 2724902
RU Russia 143.50 17125191
BY Belarus 9.50 207600
UA Ukraine 45.50 603628
Особо ленивые могут просто написать del df['density'].
Переименовывать столбцы нужно через метод rename:
>>> df = df.rename(columns={'Country Code': 'country_code'})
>>> df
country_code country population square
0 KZ Kazakhstan 17.04 2724902
1 RU Russia 143.50 17125191
2 BY Belarus 9.50 207600
3 UA Ukraine 45.50 603628
В этом примере перед тем как переименовать столбец Country Code, убедитесь, что с него сброшен индекс, иначе не будет никакого эффекта.
Чтение и запись данных
pandas поддерживает все самые популярные форматы хранения данных: csv, excel, sql, буфер обмена, html и многое другое:
Чаще всего приходится работать с csv-файлами. Например, чтобы сохранить наш DataFrame со странами, достаточно написать:
>>> df.to_csv('filename.csv')
Функции to_csv ещё передаются различные аргументы (например, символ разделителя между колонками) о которых подробнее можно узнать в официальной документации.
Считать данные из csv-файла и превратить в DataFrame можно функцией read_csv.
>>> df = pd.read_csv('filename.csv', sep=',')
Аргумент sep указывает разделитесь столбцов. Существует ещё масса способов сформировать DataFrame из различных источников, но наиболее часто используют CSV, Excel и SQL. Например, с помощью функции read_sql, pandas может выполнить SQL запрос и на основе ответа от базы данных сформировать необходимый DataFrame. За более подробной информацией стоит обратиться к официальной документации.
Группировка и агрегирование в pandas
Группировка данных один из самых часто используемых методов при анализе данных. В pandas за группировку отвечает метод .groupby. Я долго думал какой пример будет наиболее наглядным, чтобы продемонстрировать группировку, решил взять стандартный набор данных (dataset), использующийся во всех курсах про анализ данных — данные о пассажирах Титаника. Скачать CSV файл можно тут.
>>> titanic_df = pd.read_csv('titanic.csv')
>>> print(titanic_df.head())
PassengerID Name PClass Age \
0 1 Allen, Miss Elisabeth Walton 1st 29.00
1 2 Allison, Miss Helen Loraine 1st 2.00
2 3 Allison, Mr Hudson Joshua Creighton 1st 30.00
3 4 Allison, Mrs Hudson JC (Bessie Waldo Daniels) 1st 25.00
4 5 Allison, Master Hudson Trevor 1st 0.92
Sex Survived SexCode
0 female 1 1
1 female 0 1
2 male 0 0
3 female 0 1
4 male 1 0
Необходимо подсчитать, сколько женщин и мужчин выжило, а сколько нет. В этом нам поможет метод .groupby.
>>> print(titanic_df.groupby(['Sex', 'Survived'])['PassengerID'].count())
Sex Survived
female 0 154
1 308
male 0 709
1 142
Name: PassengerID, dtype: int64
Термин "сводная таблица" хорошо известен тем, кто не по наслышке знаком с инструментом Microsoft Excel или любым иным, предназначенным для обработки и анализа данных. В pandas сводные таблицы строятся через метод .pivot_table. За основу возьмём всё тот же пример с Титаником. Например, перед нами стоит задача посчитать сколько всего женщин и мужчин было в конкретном классе корабля:
В качестве индекса теперь у нас будет пол человека, колонками станут значения из PClass, функцией агрегирования будет count (подсчёт количества записей) по колонке Name.
В pandas очень удобно анализировать временные ряды. В качестве показательного примера я буду использовать цену на акции корпорации Apple за 5 лет по дням. Файл с данными можно скачать тут.
>>> import pandas as pd
>>> df = pd.read_csv('apple.csv', index_col='Date', parse_dates=True)
>>> df = df.sort_index()
>>> print(df.info())
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1258 entries, 2017-02-22 to 2012-02-23
Data columns (total 6 columns):
Open 1258 non-null float64
High 1258 non-null float64
Low 1258 non-null float64
Close 1258 non-null float64
Volume 1258 non-null int64
Adj Close 1258 non-null float64
dtypes: float64(5), int64(1)
memory usage: 68.8 KB
Здесь мы формируем DataFrame с DatetimeIndex по колонке Date и сортируем новый индекс в правильном порядке для работы с выборками. Если колонка имеет формат даты и времени отличный от ISO8601, то для правильного перевода строки в нужный тип, можно использовать метод pandas.to_datetime.
Давайте теперь узнаем среднюю цену акции (mean) на закрытии (Close):
Resampling мощный инструмент при работе с временными рядами (time series), помогающий переформировать выборку так, как удобно вам. Метод resample первым аргументом принимает строку rule. Все доступные значения можно найти в документации.
Визуализация данных в pandas
Для визуального анализа данных, pandas использует библиотеку matplotlib. Продемонстрирую простейший способ визуализации в pandas на примере с акциями Apple.
Берём цену закрытия в промежутке между 2012 и 2017.
По оси X, если не задано явно, всегда будет индекс. По оси Y в нашем случае цена закрытия. Если внимательно посмотреть, то в 2014 году цена на акцию резко упала, это событие было связано с тем, что Apple проводила сплит 7 к 1. Так мало кода и уже более-менее наглядный анализ ;)
Эта заметка демонстрирует лишь малую часть возможностей pandas. Со своей стороны я постараюсь по мере своих сил обновлять и дополнять её.
Эту заметку я пишу для того, чтобы продемонстрировать пошаговую установку и настройку виртуальной машины в Linux на базе KVM. Ранее я уже писал про виртуализацию, где использовал замечательный инструмент Vagrant.
Сейчас передо мной встал вопрос аренды хорошего сервера с большим объёмом оперативной памяти и объёмным жестким диском. Но запускать проекты прямо на хост-машине не хочется, поэтому буду разграничивать их по отдельным небольшим виртуальным серверам с ОС Linux или docker-контейнерам (о них расскажу в другой статье).
Все современные облачные хостинги работают по такому же принципу, т.е. хостер на хорошем железе поднимает кучу виртуальных серверов, которые мы привыкли называть VPS/VDS, и раздаёт их пользователям, либо автоматизирует этот процесс (привет, DigitalOcean).читать дальше
Начал потихоньку исполнять свой план на 2017 год с перевода статьи про работу с Celery на английский язык - Celery Best Practices: practical approach. В планах у меня начать английскую версию блога с перевода топа самых популярных статей, будут появляться по мере сил.
В последнее время стал замечать, что мой блог регулярно стали посещать пользователи из США и других англоговорящих стран, мне пока непонятно откуда они на него переходят (если кто знает как посмотреть отчёт в разрезе страна-источник в Я.Метрике, напишите, пожалуйста), но тенденция радует. Сейчас, конечно, процент отказов среди таких пользователей высокий, но постараюсь его снизить путем интересного контента.
Сегодня английский язык это не только lingua franca для коммуникации между людьми с разных стран, но и язык науки. Язык на котором в первую очередь появляется самая актуальная информация практически во всех сферах нашей жизни, проще говоря, больше всего уникального контента создаётся именно на английском. Попробую внести вклад и в эту часть Интернета, думаю это того стоит. Помимо очевидных плюсов в дополнительной аудитории и новых знакомствах, это ещё и неплохая возможность развивать дальше навык письма на неродном тебе языке.
На английскую версию блога можно перейти из верхнего меню либо по ссылке - English version.
Ровно 1 год назад появился самый первый пост в этом блоге. Удивительно, но я всё таки не забросил его. Прошлый опыт говорил об обратном. Что произошло за это время?
За этот год:
Я написал 30 постов, включая этот. Изначально я планировал чаще писать, но ввиду некоторых обстоятельств и лени этого добиться не удалось.
На момент написания этого поста блог посетило 41 123 уникальных посетителя. Хороший показатель для узкоспециализированного блога с небольшим количеством контента.
Ежедневная аудитория увеличилась с 0 до 350 уникальных посетителей.
Суммарно эти 5 статей принесли блогу 57% всех уникальных посетителей. Помните правило 80/20 ? :)
Более 85% пользователей читают статьи, используя ПК, 11% заходят через смартфон и только 3% через планшет. Это логично, так как программисты в своей работе привыкли пользоваться компьютером :)
А вот статистика по операционным системам используемых устройств:
Как ни странно, но блог я начал вести накануне Нового Года, а это время для постановки новых целей, выполнения новых задач и воплощения идей в реальность. Не буду нарушать традицию и прикину примерные цели, намеченные на 2017 год:
Создать английскую версию блога. В англоязычном сегменте Интернета куда больше трафика и людей, ищущих статьи на те или иные темы. Также это неплохая возможность и дальше практиковать письменный английский, знакомиться с новыми и интересными людьми.
Чаще писать статьи на актуальные темы для разработчиков. Тут у меня уклон больше в сторону Python. Сейчас в работе я применяю инструменты анализа данных и машинного обучения, поэтому хотелось бы раскрыть эти темы более подробно. В планах также углубление в сторону сложных интерфейсов в веб-приложениях, об этом я уже писал в заметке про progressive web apps. Серия статей на эту тему не заставит себя долго ждать :)
Больше контента, а значит и больше трафика. Цель на 2017 год - 2 000 уникальных посетителей в сутки.
В криминалистике существует интересная теория под названием "Теория разбитых окон" (ТРО). Суть её в том, что разбитое окно, при несвоевременной замене, влечёт за собой целую серию разбитых окон. Более того, серия разбитых окон может быть индикатором повышающегося уровня преступности в заданном регионе. На ум сразу приходит известная всем фраза "Чисто не там, где убирают, а там где не сорят". Согласно этой теории, чисто именно там, где убирают, стимулируя тем самым людей не сорить в будущем. Стоит заметить, что это применимо не только к окнам :) Автолюбителям наверняка знакома эта теория на дорогах, хотя они могут и не догадываться о её существовании. Я не раз замечал большое скопление автомобилей, припаркованных под знаком "Остановка запрещена". Стоит лишь одному остановиться под ним, остальные водители не заставят себя долго ждать. Удивительно как мало внимания дорожная полиция уделяет этому факту. Правонарушения должны своевременно пресекаться.
Но вернёмся всё же в мир разработки программного обеспечения. Удивительно, но и здесь ТРО находит свой отклик. Современный процесс создания ПО находится под жестким прессингом сроков. Бизнесу очень важно как можно раньше поставить продукт на рынок по ряду причин. Отсюда рождаются различные методологии управления вроде Agile, Lean, формируются концепции MVP (Minimum Viable Product). Как следствие, страдает качество кода, он начинает "протухать". С "вонючим кодом" можно жить, более того, практически всегда он есть в той или иной степени, это нормально. Но его нарастающая доля служит одним из первых индикаторов того, что пора "бить во все колокола". Почему? Основываясь на собственном опыте скажу, что программист охотнее "говнокодит" там, где этого "говнокода" предостаточно. И наоборот, человек несколько раз подумает, прежде чем отправлять свой шедевр на код ревью, если в проекте стараются соблюдать чистоту кода. Помимо прочего, "разбитое окно" в коде создаёт ощущение наплевательского отношения к проекту, тем самым порождая чувство безразличности к нему. Зачем пытаться что-то изменить, если всем наплевать?
В последнее время я всё чаще начинаю задумываться о судьбе современного Web. Привычный для нас веб потихоньку трансформируется во что-то грандиозное. Сейчас мы живём в эпоху стремительных перемен, за этим очень интересно наблюдать. Шумиха вокруг мобильных приложений, которая началась с появление iPhone и Android, потихоньку спадает. Количество приложений на смартфонах пользователей не растёт. У рядового юзера образовался определённый костяк приложений, которые он чаще всего использует: YouTube, Instagram, WhatsApp/Viber/Telegram, Facebook, VK, браузер (Chrome, Safari, Opera, Mozilla Firefox). В остальном нет необходимости. Если хочется почитать новости или развлекательный контент, всегда можно зайти на мобильную версию сайта, используя любимый браузер.
Web 1.0
Когда я был маленьким, веб был примитивным. Большая часть сайтов в Интернете была статичной. Это был стандартный и привычный по сей день механизм рендеринга страницы на стороне сервера без какой-либо динамической составляющей на стороне юзера. Пользователь, используя браузер, посылал запрос на сервер, сервер его обрабатывал и возвращал назад готовую HTML страничку. О какой-либо интерактивной составляющей, а тем более шикарном user experience и речи не было. На компьютерах рядовых пользователей доминирующую роль играли desktop приложения, распространяемые на CD/DVD дисках (помните ведь эти сборники софта?). Но время не стоит на месте. Технологии стремительно развиваются, проникновение Интернета в дома простых людей неуклонно растёт, а с этим и скорость передачи данных. С приходом новых технологий, требование к качеству продуктов растёт. В 1995 году появился язык JavaScript, который до сих пор играет ключевую роль в нашей с вами повседневной жизни (хоть многие об этом и не догадываются). Благодаря его появлению Web "ожил". На, казалось бы, "бездушных" просторах Интернета появилась душа, странички стали оживать, благодаря модели DOM и тому как JavaScript "умело" справлялся с манипулированием элементов в браузере. Но тамошние веб-приложения были далеки от desktop приложений того мира...
В последнее время Telegram начал стремительно развиваться и вводить новые плюшки для пользователей и разработчиков (например, я недавно писал о том как создать игру в Telegram). Из обычного мессенджера, коих пруд пруди, он превратился в полноценное средство продвижения информации, в простонародье, СМИ. Ведущие газеты, журналы и просто новостные сайты начали заводить в Telegram свои группы и каналы. Формат каналов в Telegram очень удобен для потребления информации, всё чинно, благородно. Более того, благодаря ботам Telegram, появилась возможность на этих самых каналах проводить опрос, а также использовать другие инструменты маркетингового анализа. Что позволяет эффективно продвигать нужный материал целевой аудитории группы или канала.
Кто бы что ни говорил, но для меня Telegram из обычного мессенджера также превратился в помойку ссылок. Что я имею в виду? А то, что благодаря кросс-платформенной архитектуре, а в Telegram всё таки есть отличный desktop-клиент, мне стало проще копить ссылки на интересные статьи, видео и новости про разработку, экономику, предпринимательство и так далее. Всё это я попросту сбрасываю самому себе в Telegram и имею возможность просматривать со всех своих устройств (ноутбук, настольный компьютер, смартфон, планшет, микроволновка :)
Чтобы это добро не пропадало даром, я решил завести отдельный Telegram канал для разработчиков, где буду собирать интересный материал на тему разработки ПО, включая статьи, новости, видео и даже книги. Публикую я всё это добро регулярно, так как частенько натыкаюсь на интересный материал в сети.
Отличительной особенностью каналов от групп является их фокус на контенте. В группах люди обычно активно общаются и чтение переписки и поиск нужной информации может занимать долгое время, в каналах же всё по-другому: всё четко и по делу, меньше слов больше контента.
За сим, приглашаю вас подписаться на мой Telegram канал @DevBrain для разработчиков.
Буквально на днях, а именно 3 октября, разработчики Telegram анонсировали новость о том, что на их платформе теперь можно создавать игры. Доступны для игры как многопользовательский режим, так и игры одиночного уровня.
Ребята не стали изобретать велосипед в виде отдельного игрового движка или чего то в этом роде. Игры в Telegram можно создавать, используя знакомую всем связку HTML5 + JavaScript. На платформе уже доступно небольшое количество игр, включая полюбившуюся мне игрушку под названием Lumberjack, где задачей является срубить как можно больше веток у дерева.
С момента последнего поста про Django Channels прошло много времени, проект развивается и потихоньку идёт к стабильному релизу. В новых версиях пакета появляются интересные фишки о которых я сегодня расскажу вкратце:
Generic Consumers
Generic Consumers чем то напоминают Class Based Views в Django. Их задача сократить количество кода при написании обработчиков каналов, а также улучшить их структуру и внешний вид.