{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: pandas",
    "home_page_url": "http:\/\/test.leftjoin.ru\/tags\/pandas\/",
    "feed_url": "http:\/\/test.leftjoin.ru\/tags\/pandas\/json\/",
    "icon": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Николай Валиотти",
        "url": "http:\/\/test.leftjoin.ru\/",
        "avatar": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "118",
            "url": "http:\/\/test.leftjoin.ru\/all\/mean-vs-median\/",
            "title": "Различия между медианой и средним арифметическим как целевым показателем анализа данных",
            "content_html": "<p>В сегодняшней статье мы бы хотели осветить простую, но в то же время важную тему выбора простой метрики для оценки того или иного датасета. Со средним арифметическим все давным давно знакомы, чуть ли не каждый школьник отлично знает, что нужно просуммировать все имеющиеся значения, поделить на их количество и получить среднее значение. В школьные знания не входят никакие альтернативные варианты, которых, на самом деле, в статистике много — на любой вкус и случай. Однако, в решении исследовательских и маркетинговых задач люди часто берут именно эту метрику за основу. Правомерно ли это или есть более удачный вариант? Давайте разбираться.<\/p>\n<p>Для начала стоит вспомнить определения двух метрик, о которых мы сегодня поговорим.<br \/>\nСреднее  — самый популярный статистический показатель, который используется для измерения центра данных. А что же такое медиана? Медиана — значение, которое разбивает данные, отсортированные по порядку увеличения значений, на две равные части. Это значит, что медиана показывает центральное значение в выборке, если наблюдений нечетное количество и среднее арифметическое двух значений, если количество наблюдений в выборке четно.<\/p>\n<h2>Исследовательские задачи<\/h2>\n<p>Итак, оценка среднего значения выборки — зачастую важна во многих исследовательских вопросах. Например, специалисты, изучающие демографию часто задаются вопросом изменения численности регионов России, чтобы проследить за динамикой и отразить это в отчетностях. Давайте попробуем рассчитать среднюю численность региона России, а также медиану, а затем сравним полученные результаты.<br \/>\nДля начала, нужно найти и загрузить данные, подключив для этого библиотеку pandas.<\/p>\n<pre class=\"e2-text-code\"><code>import pandas as pd\r\ncity = pd.read_csv('city.csv')<\/code><\/pre><p>Затем, нужно посчитать среднее и медиану выборки.<\/p>\n<pre class=\"e2-text-code\"><code>mean_pop = round(city.population_2020.mean(), 0)\r\nmedian_pop = round(city.population_2020.median(), 0)<\/code><\/pre><p>Значения, естественно, получились разными, так как распределение наблюдений в выборке отлично от нормального. Для того, чтобы понять, сильно ли они отличаются, построим график распределения и отметим среднее и медиану.<\/p>\n<pre class=\"e2-text-code\"><code>import matplotlib.pyplot as plt\r\nimport seaborn as sns\r\n\r\nsns.set_palette('rainbow')\r\nfig = plt.figure(figsize = (20, 15))\r\nax = fig.add_subplot(1, 1, 1)\r\ng = sns.histplot(data = city, x= 'population_2020', alpha=0.6, bins = 100, ax=ax)\r\n\r\ng.axvline(mean_pop, linewidth=2, color='r', alpha=0.9, linestyle='--', label = 'Среднее = {:,.0f}'.format(mean_pop).replace(',', ' '))\r\ng.axvline(median_pop, linewidth=2, color='darkgreen', alpha=0.9, linestyle='--', label = 'Медиана = {:,.0f}'.format(median_pop).replace(',', ' '))\r\n\r\nplt.ticklabel_format(axis='x', style='plain')\r\nplt.xlabel(&quot;Численность населения&quot;, fontsize=25)\r\nplt.ylabel(&quot;Количество городов&quot;, fontsize=25)\r\nplt.title(&quot;Распределение численности населения российских городов&quot;, fontsize=25)\r\nplt.legend(fontsize=&quot;xx-large&quot;)\r\nplt.show()<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/avg_p2.jpg\" width=\"1440\" height=\"1080\" alt=\"\" \/>\n<\/div>\n<p>Также, на этих данных стоит построить боксплот для более точной визуализации основных квантилей распределения, медианы, среднего и выбросов.<\/p>\n<pre class=\"e2-text-code\"><code>fig = plt.figure(figsize = (10, 10))\r\nsns.set_theme(style=&quot;whitegrid&quot;)\r\nsns.set_palette(palette=&quot;pastel&quot;)\r\n\r\nsns.boxplot(y = city['population_2020'], showfliers = False)\r\n\r\nplt.scatter(0, 550100, marker='*', s=100, color = 'black', label = 'Выбросы')\r\nplt.scatter(0, 560200, marker='*', s=100, color = 'black')\r\nplt.scatter(0, 570300, marker='*', s=100, color = 'black')\r\nplt.scatter(0, mean_pop, marker='o', s=100, color = 'red', edgecolors = 'black', label = 'Среднее')\r\nplt.legend()\r\n\r\nplt.ylabel(&quot;Численность населения&quot;, fontsize=15)\r\nplt.ticklabel_format(axis='y', style='plain')\r\nplt.title(&quot;Боксплот численности населения&quot;, fontsize=15)\r\nplt.show()<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/bp_city.jpg\" width=\"720\" height=\"720\" alt=\"\" \/>\n<\/div>\n<p>Из графиков следует, что медиана существенно меньше среднего, а также, ясно, что это следствие наличия больших выбросов — Москвы и Санкт-Петербурга. Поскольку среднее арифметическое — метрика крайне чувствительная к выбросам — при их наличии в выборке опираться на выводы относительно среднего не стоит. Рост или снижение численности населения Москвы может сильно смещать среднюю численность по России, однако это не будет влиять на настоящий общерегиональный тренд.<br \/>\nИспользуя среднее арифметическое мы скажем, что численность типичного (среднего) города в РФ — 268 тысяч человек. Однако, это вводит нас в заблуждение, так как среднее значительно превышает медиану исключительно из-за численности населения Москвы и Санкт-Петербурга. На самом деле, численность типичного российского города существенно меньше (аж в 2 раза!) и составляет 104 тысячи жителей.<\/p>\n<h2>Маркетинговые задачи<\/h2>\n<p>В контексте бизнеса разница между средним арифметическим и медианой также важна, так как использование неверной метрики может серьезно сказаться на результатах проведения акции или затруднить достижение цели. Давайте посмотрим на реальном примере, с какими трудностями может столкнуться предприниматель в ритейле, если неверно выберет целевую метрику.<br \/>\nДля начала, как и в предыдущем примере, загрузим датасет о покупках в супермаркете. Выберем необходимые для анализа столбцы датасета и переименуем их, для упрощения кода в дальнейшем. Поскольку эти данные не так хорошо подготовлены, как предыдущие, необходимо сгруппировать все купленные товары по чекам. В этом случае необходима группировка по двум переменным: по id покупателя и по дате покупки (дата и время определяется моментом закрытия чека, поэтому все покупки в рамках одного чека совпадают по дате). Затем, назовем полученный столбец «total_bill», то есть сумма чека и посчитаем среднее и медиану.<\/p>\n<pre class=\"e2-text-code\"><code>df = pd.read_excel('invoice_data.xlsx')\r\ndf_nes = df[['Номер КПП', 'Сумма', 'Дата продажи']]\r\ndf_nes.columns = ['user','total_price', 'date']\r\ngroupped_df = pd.DataFrame(df_nes.groupby(['user', 'date']).total_price.sum())\r\ngroupped_df.columns = ['total_bill']\r\nmean_bill = groupped_df.total_bill.mean()\r\nmedian_bill = groupped_df.total_bill.median()<\/code><\/pre><p>Теперь, как и в предыдущем примере нужно построить график распределения чеков покупателей и боксплот, а также отметить медиану и среднее арифметическое на каждом из них.<\/p>\n<pre class=\"e2-text-code\"><code>sns.set_palette('rainbow')\r\nfig = plt.figure(figsize = (20, 15))\r\nax = fig.add_subplot(1, 1, 1)\r\nsns.histplot(groupped_df, x = 'total_bill', binwidth=200, alpha=0.6, ax=ax)\r\nplt.xlabel(&quot;Покупки&quot;, fontsize=25)\r\nplt.ylabel(&quot;Суммы чеков&quot;, fontsize=25)\r\nplt.title(&quot;Распределение суммы чеков&quot;, fontsize=25)\r\nplt.axvline(mean_bill, linewidth=2, color='r', alpha=1, linestyle='--', label = 'Среднее = {:.0f}'.format(mean_bill))\r\nplt.axvline(median_bill, linewidth=2, color='darkgreen', alpha=1, linestyle='--', label = 'Медиана = {:.0f}'.format(median_bill))\r\nplt.legend(fontsize=&quot;xx-large&quot;)\r\nplt.show()<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/avg_invoice_33.jpg\" width=\"1440\" height=\"1080\" alt=\"\" \/>\n<\/div>\n<pre class=\"e2-text-code\"><code>fig = plt.figure(figsize = (10, 10))\r\nsns.set_theme(style=&quot;whitegrid&quot;)\r\nsns.set_palette(palette=&quot;pastel&quot;)\r\n\r\nsns.boxplot(y = groupped_df['total_bill'], showfliers = False)\r\n\r\nplt.scatter(0, 1800, marker='*', s=100, color = 'black', label = 'Выбросы')\r\nplt.scatter(0, 1850, marker='*', s=100, color = 'black')\r\nplt.scatter(0, 1900, marker='*', s=100, color = 'black')\r\nplt.scatter(0, mean_bill, marker='o', s=100, color = 'red', edgecolors = 'black', label = 'Среднее')\r\nplt.legend()\r\n\r\nplt.ticklabel_format(axis='y', style='plain')\r\nplt.ylabel(&quot;Сумма чека&quot;, fontsize=15)\r\nplt.title(&quot;Боксплот суммы чеков&quot;, fontsize=15)\r\nplt.show()<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/bp_invoice.jpg\" width=\"720\" height=\"720\" alt=\"\" \/>\n<\/div>\n<p>Из графиков следует, что распределение смещено к началу координат (отличное от нормального), а значит медиана и среднее не равны. Медианное значение меньше среднего примерно на 220 рублей.<br \/>\nТеперь представим, что у маркетологов есть задача повысить средний чек покупателя. Маркетолог может решить, что поскольку средний чек равен 601 рублю, то можно предложить следующую акцию: «Всем покупателям, кто совершит покупку на 600 рублей, мы предоставляем скидку 20% на товар за 100 рублей». В целом, резонное предложение, однако, в реальности, средний чек ниже — 378 рублей. То есть большая часть покупателей не заинтересуется в предложении, поскольку их покупка обычно не достигает предложенного порога. Это значит. что они не воспользуются предложением и не получат скидку, а компания не сможет достичь поставленной цели и увеличить прибыль супермаркета. Все дело в том, что исходные предпосылки были ошибочны.<\/p>\n<h2>Выводы<\/h2>\n<p>Как вы уже поняли, среднее арифметическое зачастую показывает более значимый и приятный результат, как для бизнеса, так и для исследовательских задач, ведь руководству всегда выгоднее представить ситуацию со средним чеком или демографической ситуацией в стране лучше, чем она есть на самом деле. Однако, необходимо всегда помнить о недостатках такой метрики, как среднее арифметическое, чтобы уметь грамотно выбрать подходящий аналог для оценки той или иной ситуации.<\/p>\n",
            "date_published": "2021-09-16T21:20:47+03:00",
            "date_modified": "2021-10-27T14:06:01+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/avg_p2.jpg",
            "_date_published_rfc2822": "Thu, 16 Sep 2021 21:20:47 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/avg_p2.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/bp_city.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/avg_invoice_33.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/bp_invoice.jpg"
                ]
            }
        },
        {
            "id": "99",
            "url": "http:\/\/test.leftjoin.ru\/all\/apple-health-export\/",
            "title": "Экспорт исторических данных Apple Health в Google Sheets",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/pic.jpg\" width=\"659\" height=\"395\" alt=\"\" \/>\n<\/div>\n<p>Для устройств на базе iOS и watchOS существует приложение Health, которое ежедневно записывает все данные о здоровье носителя и синхронизирует их со сторонними приложениями. Все эти данные в любой момент можно получить прямо из приложения в виде XML-документа. Сегодня мы выгрузим исторические данные о здоровье из приложения Apple Health, обработаем их и отправим в Google Sheets для анализа и визуализации в будущем.<\/p>\n<h2>Экспорт архива из приложения<\/h2>\n<p>Зайдите в приложение Health на iPhone. Нажмите на аватарку своего профиля в верхнем правом углу — откроется меню приложения.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/i@2x.jpg\" width=\"371\" height=\"648\" alt=\"\" \/>\n<\/div>\n<p>Внизу нажмите на кнопку «Экспортировать медданные». Через некоторое время откроется меню экспорта — отправьте архив себе на компьютер любым способом, можно по AirDrop или даже по почте в письме самому себе. Из архива нужен только один файл — «экспорт.xml». Достаньте его и положите в папку с ноутбуком jupyter.<\/p>\n<h2>Парсер XML в DataFrame<\/h2>\n<p>При помощи библиотеки XML составляем дерево на основе документа из Health. Собирать в словарь будем следующие атрибуты: тип, единица измерения, дата создания, дата начала, дата конца, значение. Проходим по всему дереву и отправляем полученные значения атрибутов в records_dict.<\/p>\n<pre class=\"e2-text-code\"><code>from xml.etree import ElementTree\r\nimport pandas as pd\r\nimport datetime\r\n\r\ntree = ElementTree.parse('экспорт.xml')\r\nroot = tree.getroot()\r\nrecords = root.findall('Record')\r\n\r\nrecords_dict = {\r\n    'type':[],\r\n    'unit':[],\r\n    'creationDate':[],\r\n    'startDate':[],\r\n    'endDate':[],\r\n    'value':[]\r\n}\r\n\r\nfor record in records:\r\n    for attribute in records_dict.keys():\r\n        attribute_value = record.get(attribute)\r\n        records_dict[attribute].append(attribute_value)<\/code><\/pre><p>События записаны в нечитабельном виде — для перевода составим специальный словарь с нужными типами, где ключ — старое название, а значение — новое. Мы возьмём только 11 событий: минуты осознанности, дистанция на велосипеде, дистанция заплыва, дистанция ходьбы и бега, пройдено пролётов, пульс, пульс в покое, шаги, активная энергия, энергия покоя и средний пульс при ходьбе.<\/p>\n<pre class=\"e2-text-code\"><code>types_dict = {\r\n    'HKCategoryTypeIdentifierMindfulSession': 'Mindful Session',\r\n    'HKQuantityTypeIdentifierDistanceCycling': 'Cycling Distance',\r\n    'HKQuantityTypeIdentifierDistanceSwimming': 'Swimming Distance',\r\n    'HKQuantityTypeIdentifierDistanceWalkingRunning': 'Walking + Running Distance',\r\n    'HKQuantityTypeIdentifierFlightsClimbed': 'Flights Climbed',\r\n    'HKQuantityTypeIdentifierHeartRate': 'Heart Rate',\r\n    'HKQuantityTypeIdentifierRestingHeartRate': 'Resting Heart Rate',\r\n    'HKQuantityTypeIdentifierStepCount': 'Steps',\r\n    'HKQuantityTypeIdentifierActiveEnergyBurned': 'Active Calories',\r\n    'HKQuantityTypeIdentifierBasalEnergyBurned': 'Resting Calories',\r\n    'HKQuantityTypeIdentifierWalkingHeartRateAverage': 'Walking Heart Rate Average'\r\n}<\/code><\/pre><p>Для минут осознанности в поле значения записей нет — мы сами посчитаем позже это поле как разницу даты окончания и начала события. Разница будет представлена как timedelta, поэтому напишем функцию перевода timedelta в минуты:<\/p>\n<pre class=\"e2-text-code\"><code>def td_to_m(td):\r\n    seconds = td.seconds + td.days * 24 * 60 * 60\r\n    return seconds \/\/ 60<\/code><\/pre><p>Из словаря создаём DataFrame и задаём названия колонок. Оставляем только те 11 событий, которые есть в словаре types_dict и приводим все колонки к нужным типам данных:<\/p>\n<pre class=\"e2-text-code\"><code>df = pd.DataFrame(records_dict)\r\ndf.columns = ['type', 'unit', 'date', 'start', 'end', 'value']\r\ndf = df[df['type'].isin(types_dict.keys())]\r\ndf['value'] = df['value'].astype(float)\r\ndf['date'] = df['date'].astype('datetime64')\r\ndf['date'] = df['date'].dt.date\r\ndf['start'] = df['start'].astype('datetime64')\r\ndf['end'] = df['end'].astype('datetime64')\r\ndf['unit'] = df['unit'].astype(str)<\/code><\/pre><p>Данные Health при экспорте никак не группируются — мы сделаем это самостоятельно. DataFrame можно поделить на три: в первом будут события, у которых единица измерения «количество в минуту» — для таких событий нужно искать среднее значение. В другой группе будут минуты осознанности — считаем число минут в каждой записи и суммируем. В последней группе находятся все остальные записи, связанные с количественными событиями — шаги, дистанция ходьбы и бега и так далее. Их тоже суммируем.<\/p>\n<pre class=\"e2-text-code\"><code>df_1 = df[df['unit'] == 'count\/min']\r\ndf_1 = df_1.groupby(by=['date', 'type', 'unit'], as_index=False).agg({'start':'min',\r\n                                                                      'end':'max',\r\n                                                                      'value':'mean'})\r\n\r\ndf_2 = df[df['type'] == 'HKCategoryTypeIdentifierMindfulSession']\r\ndf_2['value'] = df_2['end'] - df_2['start']\r\ndf_2['value'] = df_2['value'].map(td_to_m)\r\ndf_2 = df_2.groupby(by=['date', 'type', 'unit'], as_index=False).agg({'start':'min',\r\n                                                                     'end':'max',\r\n                                                                     'value':'sum'})\r\ndf_3 = df[(df['unit'] != 'count\/min') &amp; (df['type'] != 'HKCategoryTypeIdentifierMindfulSession')]\r\ndf_3 = df_3.groupby(by=['date', 'type', 'unit'], as_index=False).agg({'start':'min',\r\n                                                                      'end':'max',\r\n                                                                      'value':'sum'})\r\ndf = pd.concat([df_1, df_2, df_3])<\/code><\/pre><p>Дату создания записи переводим в строковый тип. Все наименования типов событий заменяем согласно словарю types_dict. В переменную dates записываем все уникальные даты.<\/p>\n<pre class=\"e2-text-code\"><code>df['date'] = df['date'].astype(str)\r\ndf['type'] = df['type'].apply(lambda x: types_dict[x])\r\ndates = df['date'].unique()<\/code><\/pre><p>В результате нужен словарь с колонкой даты и отдельной колонкой под каждое из 11 событий:<\/p>\n<pre class=\"e2-text-code\"><code>result = {\r\n    'date': [],\r\n    'Steps': [],\r\n    'Walking + Running Distance': [],\r\n    'Swimming Distance': [],\r\n    'Cycling Distance': [],\r\n    'Resting Calories': [],\r\n    'Active Calories': [],\r\n    'Flights Climbed': [],\r\n    'Heart Rate': [],\r\n    'Resting Heart Rate': [],\r\n    'Walking Heart Rate Average': [],\r\n    'Mindful Session': []\r\n}<\/code><\/pre><p>Проходим по каждой дате и получаем кусок DataFrame за эту дату. Добавляем её в словарь и проходим по каждому ключу, пробуя добавить значение:<\/p>\n<pre class=\"e2-text-code\"><code>for date in dates:\r\n    part = df[df['date'] == date]\r\n    result['date'].append(date)\r\n    for key in result.keys():\r\n        if key == 'date':\r\n            continue\r\n        else:\r\n            field = 'value'\r\n        try:\r\n            result[key].append(part[part['type'] == key][field].values[0])\r\n        except IndexError:\r\n            result[key].append(None)<\/code><\/pre><p>Из полученного словаря создаём DataFrame, округляем всё до двух знаков после запятой и сортируем по дате:<\/p>\n<pre class=\"e2-text-code\"><code>result_df = pd.DataFrame(result)\r\nresult_df = result_df.round(2)\r\nresult_df = result_df.sort_values(by='date')<\/code><\/pre><p>В результате получается такая таблица с историческими данными по 11 событиям:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/2-24.png\" width=\"996\" height=\"530\" alt=\"\" \/>\n<\/div>\n<h2>Экспорт DataFrame в Google Sheets<\/h2>\n<p class=\"note\">Для экспорта в Google Docs необходим сервисный аккаунт и json-файл с ключом. О том, как его получить, мы писали в материале <a href=\"http:\/\/test.leftjoin.ru\/all\/get-data-from-vk\/\" class=\"nu\">«<u>Собираем данные по рекламным кампаниям ВКонтакте<\/u>»<\/a><\/p>\n<p>Создайте новый документ в Google Sheets. Весь DataFrame можно вставить одним действием при помощи методов библиотеки gspread. Импортируйте её, а также укажите идентификатор документа и json-файл с ключом. В методе get_worksheet указывается порядковый номер листа в файле начиная с нуля.<\/p>\n<pre class=\"e2-text-code\"><code>import pandas as pd\r\nimport gspread\r\nfrom gspread_dataframe import set_with_dataframe\r\ngc = gspread.service_account(filename='serviceAccount.json')\r\nsh = gc.open_by_key('1osKA63LQkUC0FC0eIZ63jEJwn1TeIkUvqCV6ur')\r\nworksheet = sh.get_worksheet(0)<\/code><\/pre><p>В итоге в Google Spreadsheets появится такая таблица:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/--2021-03-03--15.31.48.png\" width=\"1375\" height=\"761\" alt=\"\" \/>\n<\/div>\n<p>А в следующем материале посмотрим, как наладить ежедневный экспорт данных Здоровья в эту таблицу при помощи шорткатов и Google AppScript!<\/p>\n",
            "date_published": "2021-03-03T16:57:03+03:00",
            "date_modified": "2021-03-03T17:00:07+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/ios@2x-1.jpg",
            "_date_published_rfc2822": "Wed, 03 Mar 2021 16:57:03 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "99",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/ios@2x-1.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/ios.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/pic.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/i@2x.jpg",
                    "http:\/\/test.leftjoin.ru\/pictures\/2-24.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-03-03--15.31.48.png"
                ]
            }
        },
        {
            "id": "60",
            "url": "http:\/\/test.leftjoin.ru\/all\/pandas-profiling-2\/",
            "title": "Обзор библиотеки pandas-profiling на примере датасета Superstore Sales",
            "content_html": "<p>Перед тем как работать с данными, необходимо составить представление, с чем мы имеем дело. В материале будем рассматривать датасет SuperStore Sales, а именно его лист <i>Orders<\/i>. В нём собраны данные о покупках клиентов канадского интернет-супермаркета: идентификаторы заказа, товаров, клиента, тип доставки, цены, категории и названия продуктов и прочее. Подробнее с датасетом можно ознакомиться на <a href=\"https:\/\/github.com\/PacktPublishing\/Tableau-10-Best-Practices\/blob\/master\/Chapter%205\/Sample%20-%20Superstore%20Sales%20(Excel).xls\">GitHub<\/a>. Например, если мы создадим из датасета DataFrame, можем воспользоваться стандартным методом <span class=\"inline-code\">describe()<\/span> библиотеки pandas для описания данных:<\/p>\n<pre class=\"e2-text-code\"><code>import pandas as pd\r\n\r\ndf = pd.read_csv('superstore_sales_orders.csv', decimal=',')\r\ndf.describe(include='all')<\/code><\/pre><p>И во многих случаях получим такую кашу:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/1-13.png\" width=\"984\" height=\"427\" alt=\"\" \/>\n<\/div>\n<p class=\"note\">Код библиотеки доступен на <a href=\"https:\/\/github.com\/pandas-profiling\/pandas-profiling\">GitHub<\/a><\/p>\n<p>Если постараться и потратить время, можно извлечь полезную информацию. Например, можем узнать, что люди чаще выбирают «Regular air» в качестве доставки или что большинство заказов поступило из провинции Онтарио. Тем не менее, есть и другое решение, которое подробнее и качественнее описывает датасет — библиотека pandas-profiling. Вы отдаёте ей DataFrame, а она генерирует html-страницу с подробным описанием сета данных:<\/p>\n<pre class=\"e2-text-code\"><code>import pandas_profiling\r\nprofile = pandas_profiling.ProfileReport(df)\r\nprofile.to_file(&quot;output.html&quot;)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/2-15.png\" width=\"973\" height=\"621\" alt=\"\" \/>\n<\/div>\n<p>Всего Pandas Profiling возвращает 6 разделов: обзор датасета, переменные, отношения и корреляцию между ними, количество пропущенных значений и примеры из датасета.<\/p>\n<p class=\"note\">Web-версия отчёта доступна <a href=\"http:\/\/test.leftjoin.ru\/files\/superstore.html\">по ссылке<\/a><\/p>\n<h2>Обзор данных<\/h2>\n<p>Рассмотрим первый подраздел — «Overview». Библиотека собрала следующую статистику: количество переменных, наблюдений, пропущенных ячеек, дубликатов и общий вес файла. В колонке <span class=\"inline-code\">Variable types<\/span> описаны типы переменных: здесь 12 качественных и 9 числовых.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/3-13.png\" width=\"737\" height=\"356\" alt=\"\" \/>\n<\/div>\n<p>В подразделе «Reproduction» собрана техническая информация библиотеки: сколько времени занял анализ сета данных, версия библиотеки и прочее.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/4-8.png\" width=\"725\" height=\"293\" alt=\"\" \/>\n<\/div>\n<p>А подраздел «Warnings» сообщает о возможных проблемах в структуре датасета: сейчас он, например, предупреждает, что у поля «Order Date» — слишком большое количество уникальных значений.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/5-9.png\" width=\"712\" height=\"485\" alt=\"\" \/>\n<\/div>\n<h2>Переменные<\/h2>\n<p>Двигаемся ниже. В этом разделе содержится подробное описание каждой переменной: сколько возможных уникальных значений она принимает, сколько значений пропущено, сколько памяти занимает поле. Справа от статистики присутствует гистограмма с распределением значений поля.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/6-8.png\" width=\"722\" height=\"282\" alt=\"\" \/>\n<\/div>\n<p>При нажатии на <span class=\"inline-code\">Toggle details<\/span> откроется расширенная информация: квартили, медиана и прочая полезная описательная статистика. В остальных вкладках находятся гистограмма из основного экрана, топ-10 значений по частоте и экстремальные значения.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/7-4.png\" width=\"737\" height=\"404\" alt=\"\" \/>\n<\/div>\n<h2>Отношения переменных<\/h2>\n<p>В этом разделе визуализированы отношения переменных при помощи hexbin plot: выглядит это не очень очевидно и понятно. Особенно усугубляет положение отсутствие легенды к графику.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/Screenshot-2020-09-04-at-14.56.01.png\" width=\"716\" height=\"548\" alt=\"\" \/>\n<\/div>\n<h2>Корреляция переменных<\/h2>\n<p>В этом разделе представлена по-разному посчитананя корреляция переменных: например, первым указано r-value Пирсона. Заметно, что переменная Profit положительно коррелирует с переменной <span class=\"inline-code\">Sales<\/span>. При нажатии на <span class=\"inline-code\">Toggle correlation descriptions<\/span> открывается подробное пояснение к каждому коэффициенту.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/8-5.png\" width=\"739\" height=\"554\" alt=\"\" \/>\n<\/div>\n<h2>Пропущенные значения<\/h2>\n<p>Тут всё просто — bar chart, матрица и дендрограмма с количеством заполненных полей в каждой переменной. Заметно, что в колонке <span class=\"inline-code\">Product Base Margin<\/span> отсутствуют три значения.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/9-5.png\" width=\"739\" height=\"411\" alt=\"\" \/>\n<\/div>\n<h2>Примеры<\/h2>\n<p>И, наконец, последний раздел представляет первые и последние 10 значений в качестве примера кусков сета данных — аналог метода <span class=\"inline-code\">head()<\/span> из pandas.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/10-4.png\" width=\"661\" height=\"469\" alt=\"\" \/>\n<\/div>\n<h2>Что в итоге?<\/h2>\n<p>Библиотека уделяет больше внимания статистике, чем pandas: можно получить подробную описательную статистику по каждой переменной, посмотреть, как коррелируют между собой столбцы датасета. В совокупности с генерацией простого и удобного интерфейса библиотека строит полноценный отчёт по датасету, уже на основании которого можно делать выводы и сформировать представление о данных.<br \/>\nИ всё же, у библиотеки есть и минусы. На генерацию отчётов к громадным датасетам может уйти много времени вплоть до нескольких часов. Это безусловно хороший инструмент для автоматического проектирования, но он не может сделать полноценный анализ за вас и добавить больше деталей в графики. Кроме того, если вы только начали практиковаться с анализом данных лучше будет начать с pandas — это закрепит ваши навыки и придаст уверенности при работе с данными.<\/p>\n",
            "date_published": "2020-09-04T17:55:08+03:00",
            "date_modified": "2020-09-04T18:01:13+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/2-14.png",
            "_date_published_rfc2822": "Fri, 04 Sep 2020 17:55:08 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "60",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/2-14.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2@2x.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2@1.5x.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/1-13.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2-15.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/3-13.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/4-8.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/5-9.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/6-8.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/7-4.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/Screenshot-2020-09-04-at-14.56.01.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/8-5.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/9-5.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/10-4.png"
                ]
            }
        }
    ],
    "_e2_version": 3365,
    "_e2_ua_string": "E2 (v3365; Aegea)"
}