Аналитик-экономист Саша устроилась на новую работу, у неё не было навыков программирования. В описании вакансии умение писать код не требовалось. Программирование преследовало экономиста в школе и университете. Саша старательно отмахивалась от написания кода, но избежать кодинга не вышло.
В Сашин первый день предыдущий сотрудник оставил три скрипта на Python для подготовки отчетности, уволился и сменил номер телефона. Ближайших срок сдачи отчетности – через месяц. Запуска кода было недостаточно для подготовки отчетов, нужно адаптировать скрипт под запрос руководителя.
Статья описывает ошибки, которые совершила Саша при изучение Python, и пути исправления этих ошибок. Статья расскажет об экстремальном опыте погружения в программирование на Python: анализ данных и визуализацию. Вот как это было…
Задача
Задание: провести ABC-анализ товаров по объёму выручки для оценки важности продуктов.
АВС-анализ – сортировка товаров от большего к меньшему по доле в выручке и разделение продуктов на 3 группы:
Данные: дата продажи, компания-покупатель, город покупателя, выручка и др.
1. Отрицание: отсутствие анализа инструментов
Представьте, человек, который раньше не писал программный код, открывает файл и видит нечто страшное и непонятное. Оно написано на инопланетном языке и выглядит так:
abc_per = []
good_list = pd.DataFrame({'good': df['good'].unique()})
for i in range (good_list.shape[0]):
abc = sum(df['revenue'][df['good'] == good_list['good'][i]])/sum(df['revenue'])
abc_per.append(round(abc*100,1))
good_list['abc_per'] = abc_per
good_list = good_list.sort_values(by = 'abc_per', ascending = False)
Первая реакция – отрицание. Экономист отказывается от изучения Python и пытается решить задачу в Excel. Саша работает в этой программе 2 года.
Сначала процесс идёт быстро: экономист готовит таблицы и пишет формулы. Но объем данных составляет 500 тыс. строк и выполнять обработку в Excel трудоемко. Программа зависает и вылетает в 70% случаев. Появляется ещё одна проблема: информация за разные периоды лежит в отдельных файлах. При попытке склеить эти файлы базовыми средствами Excel появляются новые ошибки.
Спустя 3 часа тщетных попыток выполнить расчет, экономист решает выйти из зоны комфорта и взяться за изучение Python.
Ошибка
Для решения задачи не проведен анализ инструментов. Экономист не оценил плюсы и минусы Excel и Python, не поискал в интернете другие программы.
Как исправить
Открыть Google и узнать, что для проведения ABC-анализа, кроме Excel и Python, подходят Power Query и SQL. Эти программы помогут объединить файлы и обработать объем данных в полмиллиона строк.
Важно: аналитик выбирает инструмент на основе своих предпочтений. Мы не называем этот выбор правильным или неправильным. Просто полагаем, что поиск разных решений помогает получить новые знания.
Power Query – дополнение к Excel, помогает преобразовывать и объединять данные из отдельных файлов. Power Query не требует навыков программирования. У программы русскоязычный интерфейс, похожий на другие продукты Microsoft.
SQL – язык структурированных запросов, используется для анализа данных. Также преобразовывает и объединяет данные. Придется программировать, но язык похож на английский. SQL использует команды: create, drop, select, join и пр.
2. Гнев: чужие коды и непоследовательное погружение
Экономист открывает код и внимательно читает его от начала до конца. Ничего не понимает, разбивает скрипт на отдельные элементы и старается изучить каждый из них в отдельности. Через 8 часов Саша разбирает 40% кода, выяснила предназначение библиотек и функций.
В середине кода оказалась строка:
good_list_new['abc_group'] = good_list_new['abc_per_accum'].apply(
lambda abc: 'A' if abc < 80 else('B' if 80 <= abc < 95 else 'C'))
Экономист не понимает, что еще за lambda. В интернете не оказалось нужного Саше ответа на вопрос о том, зачем нужна lambda и что она делает. Пример статьи о lambda:
У экономиста возникает ряд вопросов. Функция? Аргумент? Выражение? Объект-функция? Саша злится, захлопывает крышку ноутбука и неделю не возвращается к изучению Python.
Ошибка
Погружение в программирование началось с конкретного кода и разбора его отдельных элементов. Фокус внимания направлен на чужое готовое решение, а не на понимание концепции и терминологии Python.
Как исправить
Сначала нужно узнать, что Python – объектно-ориентированный язык программирования. Затем разобраться в этом термине, составить собственный словарь понятий и их объяснений.
Объектно-ориентированный язык программирования означает, что программный код состоит из объектов, которые взаимодействуют между собой. Примеры объектов: человек, почтовый индекс, компания или автомобиль.
Свойства – характеристики объекта, методы – возможные действия с объектом. Класс – набор свойств и методов для всех объектов, входящих в класс.
Объект – красный Jeep 2010 года выпуска, который купил Иванов И.И. Свойства объекта: цвет – красный, марка – Jeep, год выпуска – 2010, владелец – Иванов И.И.. Метод объекта: покупка. Класс: автомобиль. Свойства класса: цвет, марка, год выпуска, владелец, объем двигателя, число лошадиных сил и пр. Методы класса: купить, разбить, продать.
Следующий этап – изучение элементов Python:
Переменные,
Типы данных,
Операторы,
Функции.
Теперь стоит написать первые строки собственного кода. После двух часов самостоятельных упражнений с переменными и функциями можно приступить к разбору чужого кода.
Важно: начинать погружение в свой первый язык программирования с изучения чужого кода – спорный подход. Но анализировать код «со стороны» полезно на следующих этапах изучения. Это помогает узнать о новых решениях и оптимизировать свой код. Анализ скриптов других аналитиков повышает «насмотренность».
3. Торг: сторонние программы и ручные решения
Спустя неделю Саша возвращается к Python, ведь срок сдачи отчетов приближается. Саша не пишет чистый код Python из-за скромного опыта в программировании, на помощь приходят «костыли». «Костыли» – особенности кода, которые делают решение менее универсальным: использование сторонних программ и необходимость вручную корректировать код.
Примеры:
Экономист создает код для выполнения расчетов, но результаты этих расчетов анализирует с помощью сводных таблиц в Excel.
Саша подгружает данные в Python, использует циклы и условные конструкции, но базовые визуализации для проверки строит в Power BI.
Аналитик выгружает данные в виде csv-файла из хранилища данных с помощью SQL, затем анализирует в Python.
Саша использует первый вариант, потому что уверена в своих знаниях Excel. Однако, Python предлагает решения на этот случай: функции pivot_table или crosstab из библиотеки pandas. Для второго случая используются библиотеки matplotlib или seaborn, для третьей проблемы – psycopg2 или sqlalchemy.
Комбинированные решения требуют повышенного внимания. Нужно проверять правильность и полноту данных при переходе из одной программы в другую.
«Костыль» может быть и внутри скрипта Python, он заставляет корректировать код вручную при любом изменении данных. Например, нужно загрузить файл без лишних столбцов и с правильными названиями колонок. Вот, что делает Саша:
df = pd.read_excel('D:/Python/Good_revenue.xlsx')
df.head()
Получается таблица:
Проблемы: пустой столбец и странные названия колонок. Саша решает проблему так:
df.drop('Unnamed: 0', axis = 1, inplace = True)
df.drop(0, axis = 0, inplace = True)
df.rename({'Unnamed: 1': 'date', 'Unnamed: 2': 'company', 'Unnamed: 3': 'city',
'Unnamed: 4': 'region', 'Unnamed: 5': 'category', 'Unnamed: 6': 'good',
'Unnamed: 7': 'price', 'Unnamed: 8': 'quantity', 'Unnamed: 9': 'revenue'},
axis = 1, inplace = True)
Саша думает: «Решение работает отлично!» Но экономист создал код, в котором много ручного труда и которые не получится использовать для других данных.
Альтернативное решение:
df = pd.read_excel('D:/Python/Good_revenue.xlsx', header=1, usecols="B:J")
df.head()
Получается таблица:
Новое решение короче изначального в 10 раз, применимо к любым данным и позволяет глубже понять функцию read_excel.
Ошибка
Использование промежуточных решений – «костылей». Это приводит к ошибкам, низкому уровню автоматизации и универсальности кода.
Как исправить
Если используются две программы, стоит разузнать о решениях внутри Python. Библиотеки уже содержат методы, похожие на функции Excel или Power Query, на графики Power BI и пр.
Важно: есть случаи, когда другие программы нужны. Например, визуализация финальных результатов для директора: Power BI или Power Point.
Если код состоит из блоков, которые редактируются вручную в 50% случаев, стоить изучить документацию функций. Еще один вариант – пользовательские функции.
Документация функций – подробное описание функции и ее аргументов с примерами. В Jupyter Notebook для вывода документации нужно написать имя функции, знак «?» и запустить ячейку:
pd.read_excel?
Результат:
Signature:
pd.read_excel(
io,
sheet_name: 'str | int | list[IntStrT] | None' = 0,
header: 'int | Sequence[int] | None' = 0,
names=None,
index_col: 'int | Sequence[int] | None' = None,
usecols=None
...
Пользовательская функция – функция, которую пользователь пишет самостоятельно. Для задания функции используется def:
def calculate_sum(a,b):
sum = a+b
return sum
Вывод функции:
print(calculate_sum(2,3))
Результат: 5
Не нужно изменять функцию и переписывать ее вручную. Достаточно менять аргументы и запускать код. В примере использована простая функция, поэтому эффект незаметен. Но если в функции стоит расчет из 20 строк с 5 переменными, рост универсальности и автоматизации будет ощутим.
4. Депрессия: бесструктурность и небрежность кода
Остается неделя до сдачи отчетности, Саша отчаивается. Кажется, что разобраться с кодом не выйдет: чем больше экономист корректирует скрипт, тем сильнее путается в нем. Треть кода работает без перебоев, но в остальной части – неразбериха. Новые переменные, длинные строки, дублирование ячеек, ветвление кода. Саша удаляет одно, перестает работать другое.
Несмотря на оптимизацию и адаптацию части кода, разобраться не выходит. Изначальный код:
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
df = pd.read_excel('D:/Python/Good_revenue.xlsx', header=1, usecols="B:J")
df['date'] = pd.to_datetime(df['date'], dayfirst = True, infer_datetime_format=True)
df = df.astype({'price': np.float, 'quantity': np.int64, 'revenue': np.float})
pd.DataFrame(round(df.isna().mean()*100,)).style.background_gradient('coolwarm')
abc_per = []
good_list = pd.DataFrame({'good': df['good'].unique()})
for i in range (good_list.shape[0]):
abc = sum(df['revenue'][df['good'] == good_list['good'][i]])/sum(df['revenue'])
abc_per.append(round(abc*100,1))
good_list['abc_per'] = abc_per
good_list = good_list.sort_values(by = 'abc_per', ascending = False)
good_list_new = good_list.reset_index(drop = True)
good_list_new['abc_per_accum'] = good_list_new['abc_per'].cumsum()
good_list_new['abc_group'] = good_list_new['abc_per_accum'].apply(lambda abc:
'A' if abc < 80 else('B' if 80 <= abc < 95 else 'C'))
Анализируем структуру кода, пробуем упростить, находим проблемы в строках:
10. Анализ пустых ячеек – опциональный элемент, можно вынести из расчета.
12-18. Эта часть кода создает уникальный список товаров и рассчитывает долю каждого товара в выручке. Используются 4 новых объекта: списки abc_per и good_list, переменная abc и столбец good_list['abc_per']. В конце – сортировка результатов.
20. Новая переменная good_list_new.
Остальные части кода нужные, но не хватает комментариев.
Попробуем применить знания из предыдущих пунктов и упростить код. Заодно добавим структуру и комментарии:
# импортируем библиотеки
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
# загружаем файл, первая строка - зоголовок, нужные колонки - B:J
# df - изначальный датасет
df = pd.read_excel('D:/Python/Good_revenue.xlsx', header=1, usecols="B:J")
# меняем типы данных, дата - datetime, цена и выручка - вещ. число, кол-во - целое
df['date'] = pd.to_datetime(df['date'], dayfirst = True, infer_datetime_format=True)
df = df.astype({'price': np.float, 'quantity': np.int64, 'revenue': np.float})
# создаем сводную таблицу category_abc, строки - товары, значения - сумма выручки
category_abc = df.pivot_table(index = 'good', values = 'revenue',
aggfunc = 'sum').sort_values(by='revenue', ascending=False)
# добавляем в сводную таблицу столбец percent с процентом выручки товара
category_abc['percent']=round((category_abc['revenue']/
sum(category_abc['revenue']))*100,4)
# расчитываем накомпительный процент выручки - столбец accumulated_percent
category_abc['accumulated_percent']=category_abc['percent'].cumsum()
# присваиваем группу ABC по накопленному процент выручки
category_abc['abc_group'] = category_abc['accumulated_percent'].apply(lambda abc:
'A' if abc < 80 else('B' if 80 <= abc < 95 else 'C'))
Визуально новый код больше изначального, но количество строк с расчетом сократилось вдвое, а читаемость кода выросла. Выкидываем цикл, не создаем новых сущностей: используем одну сводная таблица и 3 новых столбца в ней.
Ошибка
Нечитаемый код без четкой структуры:
Как исправить
Навести порядок в коде, убрать лишние блоки и подписать нужные. Внимательно относится к новым переменным и подписывать, зачем они нужны. Структурировать код:
Важно: в дальнейшем для оформления кода можно использовать PEP 8 – руководство по стилю кода Python. Для анализа кода есть продвинутые инструменты pycodestyle, prospector и пр. Здесь же напоминаем о пользовательских функциях, они тоже увеличивают читаемость кода.
5. Принятие: отсутствие базы знаний
Саша принимает неизбежность программирования на Python, корректирует код и успевает подготовить отчеты в срок. Работа с Python движется медленно, но поступательно. Через три месяца аналитик лучше понимает код и может писать часть скрипта самостоятельно. Однако, в 4 случаях из 5 код экономиста – компиляция чужих решений из интернета. В этом нет ничего плохого, просто адаптированный чужой код запоминается хуже, чем выстраданный свой. Саша обнаруживает, что некоторые найденные скрипты работают, а другие – нет. Постепенно аналитик обрастает notebook'ами с работающими и неработающими кодами, кучей файлов и начинает путаться.
Ошибка
Отсутствие базы знаний.
Как исправить
Если код работает и решает задачу, которая часто встречается, можно добавить его в базу знаний. База знаний – файл с рабочим кодом, описанием и примерами.
# корреляционный анализ
numeric_col = ['revenue', 'price', 'quantity']
corr = df.loc[:,numeric_col].corr()
print(corr)
# один ряд на графике
sns.lineplot(data=df, x = "date", y = "revenue")
# регрессионный анализ, уравнение парной регрессии (выручка от количества)
data = df
x = df[['quantity']].values
y = df['revenue'].values
skm = LinearRegression()
skm.fit(x, y)
y_pred=skm.predict(x)
print('Уравнение регрессии = ' + str(round(skm.intercept_,1)) +
' + ' + str(round(skm.coef_[0],1)) + ' * x')
Заключение
Меня зовут Александра, я team lead BI-аналитиков, анализирую данные, визуализирую информацию, интересуюсь машинным обучением. История, которую я рассказала, реальна и произошла со мной в начале карьерного пути. Я выделила 5 ошибок, которые допустила при быстром погружении в Python:
Отказываться от поиска и сравнения разных инструментов для оптимального решения задач;
Начинать с чужого кода, а не с терминологии и концепции языка программирования;
Создавать промежуточные ручные решения, снижающие универсальность кода;
Делать скрипт нечитаемым, пренебрегать структурой;
Не сохранять удачные решения в базу знаний.
Комментарии (9)
rutexd
00.00.0000 00:00Начать погружение в питон с нуля в режиме стресса и дедлайна... Путь храбрых. Помнится мне подобным образом лет 10 назад эдак я начать изучать другой яп и так же лишь спустя некоторое время после сдачи проекта начал понимать что к чему по настоящему. К счастью такого перегруза не было - но боль я ощущаю.
Если вас успокоит, по моему ощущению даже человеку с опытом сходу понять питон задача не из лёгких. Базовые концепты - можно. Поиграться - можно. Однако (!). Когда дело заходит до реального мира и реальных библиотек, их тысяч вариаций, тысяч нюансов, тысяч непонятных и разнящихся стандартов именований и концептов - тут черт ногу сломит. Язык даёт слишком много свободы - и от этого головная боль.
Ваш первый вывод крайне важный. В вашем случае это могло бы сохранить время и главное нервные клетки и возможно даже намного проще решить задачу - но к этому надо придти с опытом. Как и последний пункт - однако работает лишь на начальных - средних этапах.
mobilkip
00.00.0000 00:00Скоро буду искать первую работу(в IT и вообще), и чувствую я что эта статья мне ОЧЕНЬ пригодится
magiavr
00.00.0000 00:00Тут мало того, что человек не знает python, не знает библиотеку pandas, так в принципе имеет смутное представление о программировании. Это как неподготовленному человеку перевести стихотворение с суахили на древнегреческий.
economist75
00.00.0000 00:00По своему опыту, толковый экономист с наставником - с нуля постигает Python за 2-3 недели, а на "уверенный" Pandas уходит около полугода. Такой специалист сам напишет UDF и сделает ее методом датафрейма, закрыв потребность в ABC-анализе раз и навсегда. Метод работает максимально просто и понятно, не забудешь никогда:
df.ABC(['Контрагент', 'Выручка'])
Именно такие UDF в итоге сделают работу аналитика на порядок легче и эффективней, чем прежняя. Python-way для аналитики однозначно быстрее, увлекательнее и дешевле чем VBA-макросятничество или веселое накликивание в PowerQuery/DAX/M, или трехэтажное формулописательство в Excel. Если они уже в активе - это хорошо: UDF для ABC-анализа появится быстрее и будет применяться чаще и шире.
Но главное - ощущение простоты и надежности решения. С Python оно выше, чем с другими упомянутыми технологиями.
psalamakhin
00.00.0000 00:00Извините, но про визуализации некорректно сравнивать python и powerbi. Основное преимущество второго - интерактивность, при чем такая, что первому и не снилась. На питоне только простейшие визуализации без интерактивности и сложных связей. На питоне выгрузка, подготовка данных - да, вполне, но визуализация - это не его, не функционально
economist75
00.00.0000 00:00Очень даже корректно. PowerBI в ru-зоне скоро будет мертв, поэтому о покойниках "...либо ничего". Но планку визуализаций он задрал очень высоко, признаю. Сам python ничего не визуализирует, а вот та же pandas поддерживает несколько бэкендов визуализации в простой обертке df.plot(), которую вынуждены были повторить почти все остальные DS-платформы. Я назову по памяти интерактивные библиотеки графиков для python/pandas: altair, bokeh, echarts, holoview, hvplot, plotly, vega. Кол-во графиков, которые умеют эти либы (больше сотни) примерно в 2 раза превышает возможности PBI. Кроме того, есть matplotlib, seaborn, которые (считается) что умеют еще пол-сотню DS-экзотики.
Если под связями вы имели ввиду готовый drill-down по связям таблиц, то это надо искать в прикладном ПО в Apache Superset, Dash или самому несложно кодить в Streamlit итп. Ах, да, все упомянутое мною ПО (кроме урезанного функционалом PowerBI) - полностью свободно и бесплатно для бизнеса. Pandas для drill-down предлагает лишь ipywidget в среде Jupyter/Lab, да пяток готовых EDA-инструментов. Все это освоить - не хватит жизни, но сопоставимый с PBI результат можно получить за погода с нуля. Сейчас самое время...
lozy_rc
00.00.0000 00:00-1Это давно уже не так. Связки streamlit+понравившаяся_библиотека, dash+plotly, panel+matplotlib(ну или любая библиотека на выбор) ну и всякие малоизвестные. Тот же streamlit можно запустить в офисе со своего компа на локальную сеть, и твой коллега сможет легко его посмотреть даже без выхода в интернет. Или сохранить plotly график как html и отправить его по почте. Наверняка есть еще способы, видел даже как делают интерактивные презентации на основе юпитера и запихивают их в html. А если майки завтра решат блокирнуть PowerBI, что можно будет сделать?
кроме как надеть деревянную ногу и попугая на шею конечноА python это сотни команд и в основном open source.
argonmaster
00.00.0000 00:00Так держать, Алексанра)
Спасибо за статью.
От себя добавлю. Гуглим про докстринги в пайтон.
Всегда пишем документацию к своим функциям
Юзаем pyCharm. Там уже встроены линтеры, авто форматирование кода и инструменты для рефакторинга.
Hungryee
Отличная статья, хорошие примеры.
Отдельный респект за включение фрагментов кода