Как в питоне выгрузить двухъярусную таблицу
Перейти к содержимому

Как в питоне выгрузить двухъярусную таблицу

  • автор:

Как двухмерный python массив преобразовать в HTML таблицу?

Как заполнить эти данные в html таблицу, где индекс обозначает ряд и столбец клетки со значением? Если можно пример кода. Спасибо.

Отслеживать
77k 6 6 золотых знаков 57 57 серебряных знаков 123 123 бронзовых знака
задан 24 апр 2018 в 17:21
DmitriyLeaf DmitriyLeaf
136 1 1 золотой знак 1 1 серебряный знак 12 12 бронзовых знаков

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Самое простое решение:

relations_table = [[25, 98, 40, 17, 66, 65, 41, 11, 70, 58], [89, 93, 35, 89, 40, 17, 66, 65, 41, 99]] html = '' for row in relations_table: html += '' for value in row: html += ''.format(value) html += '' html += '
<>
' print(html)

Другой вариант, более удобный для сложных данных – шаблонизатор jinja:

# pip install jinja2 import jinja2 template = jinja2.Template('''    > ''') html = template.render(relations_table=relations_table) print(html) 

Вот так будет выглядеть таблица в браузере:

введите сюда описание изображения

Можно и более сложные штуки создавать. Пример генерации html страницы через jinja2

Изменение формы и объединение таблиц — Python: Pandas

В работе с данными приходится собирать их из разных источников и объединять в единую структуру. В библиотеке Pandas реализован функционал для таких операций над табличными данными в виде методов:

На данном уроке рассмотрим практические случаи, в которых они применяются.

Метод concat()

За основу возьмем данные о кликах на сайтах 4 магазинов за 28 дней.

df_clicks = pd.read_csv('./data/Cite_clicks.csv', index_col=0) print(df_clicks.head()) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 319.0 328.0 # 2 292.0 274.0 292.0 301.0 # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 

Разобьем исходные данные на два датафрейма за первую и вторую недели месяца. Это операция делается с использованием срезов.

df_clicks_first_week = df_clicks[:7] df_clicks_second_week = df_clicks[7:14] print(df_clicks_first_week) print(df_clicks_second_week) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 319.0 328.0 # 2 292.0 274.0 292.0 301.0 # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # 6 445.0 418.0 409.0 445.0 # 7 481.0 400.0 481.0 409.0 # # SHOP1 SHOP2 SHOP3 SHOP4 # day # 8 NaN 267.0 333.0 344.0 # 9 300.0 278.0 300.0 311.0 # 10 289.0 311.0 -278.0 289.0 # 11 344.0 388.0 344.0 333.0 # 12 421.0 377.0 399.0 355.0 # 13 487.0 454.0 -443.0 487.0 # 14 531.0 432.0 531.0 443.0 

Операция, обратная разбиению — конкатенация, применяется, чтобы собрать куски данных в единый фрагмент. Если предположить, что отчетные материалы за разные недели лежат в разных таблицах, а для аналитика необходимо поработать над всеми значениями сразу, то можно использовать метод concat() . В качестве параметров ему передается список тех датасетов, которые необходимо объединить:

df_weeks_concat = pd.concat([ df_clicks_first_week, df_clicks_second_week ]) print(df_weeks_concat) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 319.0 328.0 # 2 292.0 274.0 292.0 301.0 # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # 6 445.0 418.0 409.0 445.0 # 7 481.0 400.0 481.0 409.0 # 8 NaN 267.0 333.0 344.0 # 9 300.0 278.0 300.0 311.0 # 10 289.0 311.0 -278.0 289.0 # 11 344.0 388.0 344.0 333.0 # 12 421.0 377.0 399.0 355.0 # 13 487.0 454.0 -443.0 487.0 # 14 531.0 432.0 531.0 443.0 

Рассмотрим ситуацию, в которой данные разбиты по парам магазинов. Возможно, это данные из разных городов, и лежат они в разных таблицах баз данных:

df_clicks_two_first = df_clicks[['SHOP1', 'SHOP2']] df_clicks_two_last = df_clicks[['SHOP3', 'SHOP4']] print(df_clicks_two_first.head()) print(df_clicks_two_last.head()) # => SHOP1 SHOP2 # day # 1 319.0 -265.0 # 2 292.0 274.0 # 3 283.0 301.0 # 4 328.0 364.0 # 5 391.0 355.0 # # SHOP3 SHOP4 # day # 1 319.0 328.0 # 2 292.0 301.0 # 3 274.0 283.0 # 4 328.0 NaN # 5 373.0 337.0 

Чтобы собрать их в единое целое, применяется метод concat() , но указывается направление объединения с помощью параметра axis :

  • 0 — объединение происходит по строкам
  • 1 — по столбцам
df_shop_concat = pd.concat([ df_clicks_two_first, df_clicks_two_last ], axis=1) print(df_shop_concat.head()) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 319.0 328.0 # 2 292.0 274.0 292.0 301.0 # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 

Стоит быть внимательными с направлением объединения. Если его не указать в данном примере, то результат будет не тот, который ожидается:

print(pd.concat([ df_clicks_two_first, df_clicks_two_last ])) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 NaN NaN # 2 292.0 274.0 NaN NaN # 3 283.0 301.0 NaN NaN # 4 328.0 364.0 NaN NaN # 5 391.0 355.0 NaN NaN 

Фрагменты данных на подобии срезов по неделям и парам магазинов довольно типичная ситуация. Однако бывают случаи, когда срезы делаются по разным пересекающимся промежуткам времени. Рассмотрим данные кликов для пар магазинов за пять рабочих дней:

df_clicks_two_first = df_clicks[['SHOP1', 'SHOP2']][:5] df_clicks_two_last = df_clicks[['SHOP3', 'SHOP4']][2:7] print(df_clicks_two_first) print(df_clicks_two_last) # => SHOP1 SHOP2 # day # 1 319.0 -265.0 # 2 292.0 274.0 # 3 283.0 301.0 # 4 328.0 364.0 # 5 391.0 355.0 # # SHOP3 SHOP4 # day # 3 274.0 283.0 # 4 328.0 NaN # 5 373.0 337.0 # 6 409.0 445.0 # 7 481.0 409.0 

Здесь дни месяца не совпадают, но пересекаются. Для объединения также используется метод concat() , который объединит по соответствующим индексам и оставит пропуски в тех днях, для которых значений нет.

df_concat = pd.concat([ df_clicks_two_first, df_clicks_two_last ],axis=1) print(df_concat) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 NaN NaN # 2 292.0 274.0 NaN NaN # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # 6 NaN NaN 409.0 445.0 # 7 NaN NaN 481.0 409.0 

Метод join()

Метод concat() позволяет производить операции конкатенации по направлениям. Однако при работе с данными требуются более сложные объединения данных. Одним из методов, который поддерживает различные сценарии объединения данных по индексам, является метод join() :

df_join_to_first = df_clicks_two_first.join( df_clicks_two_last ) print(df_join_to_first) # => SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 NaN NaN # 2 292.0 274.0 NaN NaN # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 

Важно отметить, что join() не является методом Pandas, а применяется к датафрейму. Также важно, к какому датафрейму при объединении он применяется. Если поменять местами датафреймы в примере выше, то результат будет отличаться:

df_join_to_last = df_clicks_two_last.join( df_clicks_two_first ) print(df_join_to_last) # => SHOP3 SHOP4 SHOP1 SHOP2 # day # 3 274.0 283.0 283.0 301.0 # 4 328.0 NaN 328.0 364.0 # 5 373.0 337.0 391.0 355.0 # 6 409.0 445.0 NaN NaN # 7 481.0 409.0 NaN NaN 

В примерах выше в результирующем датафрейме присутствуют только индексы датафрейма, к которому применялся данный метод. Такой способ объединения называется left join и применяется по умолчанию. Метод join() поддерживает различные сценарии объединения и включает такие случаи:

  • inner join — объединение по пересечению индексов
  • right join — внешнее объединение по всем индексам объединяемых датафреймов

Для их использования в примерах ниже указываются соответствующие значения параметра how :

print('left join:') print(df_clicks_two_first.join( df_clicks_two_last, how='left' )) print('right join:') print(df_clicks_two_first.join( df_clicks_two_last, how='right' )) print('inner join:') print(df_clicks_two_first.join( df_clicks_two_last, how='inner' )) print('outer join:') print(df_clicks_two_first.join( df_clicks_two_last, how='outer' )) # => left join: # SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 NaN NaN # 2 292.0 274.0 NaN NaN # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # # right join: # SHOP1 SHOP2 SHOP3 SHOP4 # day # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # 6 NaN NaN 409.0 445.0 # 7 NaN NaN 481.0 409.0 # # inner join: # SHOP1 SHOP2 SHOP3 SHOP4 # day # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # # outer join: # SHOP1 SHOP2 SHOP3 SHOP4 # day # 1 319.0 -265.0 NaN NaN # 2 292.0 274.0 NaN NaN # 3 283.0 301.0 274.0 283.0 # 4 328.0 364.0 328.0 NaN # 5 391.0 355.0 373.0 337.0 # 6 NaN NaN 409.0 445.0 # 7 NaN NaN 481.0 409.0 

Метод merge()

Объединение данных можно производить не только по индексам, но и по столбцам значений двух датафреймов. Для этого не достаточно функционала метода join() , который может производить объединения по индексам датафреймов. Для таких случаев в Pandas используется метод merge() .

Рассмотрим датасет с кликами, в котором дни месяца указаны в столбце day , а не в индексе строк:

df_clicks = df_clicks.reset_index() print(df_clicks.head()) # => day SHOP1 SHOP2 SHOP3 SHOP4 # 0 1 319.0 -265.0 319.0 328.0 # 1 2 292.0 274.0 292.0 301.0 # 2 3 283.0 301.0 274.0 283.0 # 3 4 328.0 364.0 328.0 NaN # 4 5 391.0 355.0 373.0 337.0 

Будем решать задачу по объединению двух датасетов, содержащих пятидневные срезы по парам магазинов:

df_clicks_two_first = df_clicks[['day', 'SHOP1', 'SHOP2']][:5] df_clicks_two_last = df_clicks[['day', 'SHOP3', 'SHOP4']][2:7] print(df_clicks_two_first) print(df_clicks_two_last) # => day SHOP1 SHOP2 # 0 1 319.0 -265.0 # 1 2 292.0 274.0 # 2 3 283.0 301.0 # 3 4 328.0 364.0 # 4 5 391.0 355.0 # # day SHOP3 SHOP4 # 2 3 274.0 283.0 # 3 4 328.0 NaN # 4 5 373.0 337.0 # 5 6 409.0 445.0 # 6 7 481.0 409.0 

Для их объединения необходимо указать сперва левый, а затем правый датафреймы. Также нужно определить по каким столбцам в каждом из датафреймов будет происходить объединение.

df_merged = pd.merge( df_clicks_two_first, df_clicks_two_last, left_on='day', right_on='day' ) print(df_merged) # => day SHOP1 SHOP2 SHOP3 SHOP4 # 0 3 283.0 301.0 274.0 283.0 # 1 4 328.0 364.0 328.0 NaN # 2 5 391.0 355.0 373.0 337.0 

Также как и в методе join() в методе merge() поддерживаются различные сценарии объединения данных:

print('inner merge:') print(pd.merge( df_clicks_two_first, df_clicks_two_last, left_on='day', right_on='day', how='inner' )) print('left merge:') print(pd.merge( df_clicks_two_first, df_clicks_two_last, left_on='day', right_on='day', how='left' )) print('right merge:') print(pd.merge( df_clicks_two_first, df_clicks_two_last, left_on='day', right_on='day', how='right' )) print('outer merge:') print(pd.merge( df_clicks_two_first, df_clicks_two_last, left_on='day', right_on='day', how='outer' )) # => inner merge: # day SHOP1 SHOP2 SHOP3 SHOP4 # 0 3 283.0 301.0 274.0 283.0 # 1 4 328.0 364.0 328.0 NaN # 2 5 391.0 355.0 373.0 337.0 # # left merge: # day SHOP1 SHOP2 SHOP3 SHOP4 # 0 1 319.0 -265.0 NaN NaN # 1 2 292.0 274.0 NaN NaN # 2 3 283.0 301.0 274.0 283.0 # 3 4 328.0 364.0 328.0 NaN # 4 5 391.0 355.0 373.0 337.0 # # right merge: # day SHOP1 SHOP2 SHOP3 SHOP4 # 0 3 283.0 301.0 274.0 283.0 # 1 4 328.0 364.0 328.0 NaN # 2 5 391.0 355.0 373.0 337.0 # 3 6 NaN NaN 409.0 445.0 # 4 7 NaN NaN 481.0 409.0 # # outer merge: # day SHOP1 SHOP2 SHOP3 SHOP4 # 0 1 319.0 -265.0 NaN NaN # 1 2 292.0 274.0 NaN NaN # 2 3 283.0 301.0 274.0 283.0 # 3 4 328.0 364.0 328.0 NaN # 4 5 391.0 355.0 373.0 337.0 # 5 6 NaN NaN 409.0 445.0 # 6 7 NaN NaN 481.0 409.0 

Выводы

На данном уроке мы познакомились с различными методами Pandas для объединения табличных данных. Рассмотренные методы применяются по мере усложнения производимой операции:

  • concat() — данные объединяются по строкам или по столбцам с сохранением всех значений
  • join() — объединяюся датафреймы по индексам

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

10 приемов Python Pandas, которые сделают вашу работу более эффективной

Pandas — это широко используемый пакет Python для структурированных данных. Существует много хороших учебных пособий на данную тематику, но здесь мы бы хотели раскрыть несколько интересных приемов, которые, вероятно, еще пока неизвестны читателю, но могут оказаться крайне полезными.

read_csv

Все знают эту команду. Но если данные, которые вы пытаетесь прочитать, слишком большие, попробуйте добавить команду nrows = 5 , чтобы прочитать сначала небольшую часть данных перед загрузкой всей таблицы. В этом случае вам удастся избежать ситуации выбора неверного разделителя (не всегда в данных есть разделение в виде запятой).

(Или вы можете использовать команду ‘head’ в linux для проверки первых 5 строк в любом текстовом файле: head -c 5 data.txt )

Затем вы можете извлечь список столбцов, используя df.columns.tolist() , а затем добавить команду usecols = [‘c1’, ‘c2’,…], чтобы извлечь только нужные вам столбцы. Кроме того, если вы знаете типы данных определенных столбцов, вы можете добавить dtype = для более быстрой загрузки. Еще одно преимущество этой команды в том, что если у вас есть столбец, который содержит как строки, так и числа, рекомендуется объявить его тип строковым, чтобы не возникало ошибок при попытке объединить таблицы, используя этот столбец в качестве ключа.

select_dtypes

Если предварительная обработка данных должна выполняться в Python, то эта команда сэкономит ваше время. После чтения из таблицы типами данных по умолчанию для каждого столбца могут быть bool, int64, float64, object, category, timedelta64 или datetime64. Вы можете сначала проверить распределение с помощью

df.dtypes.value_counts()

чтобы узнать все возможные типы данных вашего фрейма, затем используйте

df.select_dtypes(include=[‘float64’, ‘int64’])

чтобы выбрать субфрейм только с числовыми характеристиками.

сopy

Это важная команда. Если вы сделаете:

import pandas as pd
df1 = pd.DataFrame(< ‘a’:[0,0,0], ‘b’: [1,1,1]>)
df2 = df1
df2[‘a’] = df2[‘a’] + 1
df1.head()

Вы обнаружите, что df1 изменен. Это потому, что df2 = df1 не делает копию df1 и присваивает ее df2, а устанавливает указатель, указывающий на df1. Таким образом, любые изменения в df2 приведут к изменениям в df1. Чтобы это исправить, вы можете сделать либо:

df2 = df1.copy ()
from copy import deepcopy
df2 = deepcopy(df1)

map

Это классная команда для простого преобразования данных. Сначала вы определяете словарь, в котором «ключами» являются старые значения, а «значениями» являются новые значения.

level_map = 
df[‘c_level’] = df[‘c’].map(level_map)

Например: True, False до 1, 0 (для моделирования); определение уровней; определяемые пользователем лексические кодировки.

apply or not apply?

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

def rule(x, y): 
if x == ‘high’ and y > 10:
return 1
else:
return 0

df = pd.DataFrame(< 'c1':[ 'high' ,'high', 'low', 'low'], 'c2': [0, 23, 17, 4]>)
df['new'] = df.apply(lambda x: rule(x['c1'], x['c2']), axis = 1)
df.head()

В приведенных выше кодах мы определяем функцию с двумя входными переменными и используем функцию apply, чтобы применить ее к столбцам ‘c1’ и ‘c2’.

но проблема «apply» заключается в том, что иногда она занимает очень много времени.

Скажем, если вы хотите рассчитать максимум из двух столбцов «c1» и «c2», конечно, вы можете применить данную команду

df[‘maximum’] = df.apply(lambda x: max(x[‘c1’], x[‘c2’]), axis = 1)

но это будет медленнее, нежели:

df[‘maximum’] = df[[‘c1’,’c2']].max(axis =1)

Вывод: не используйте команду apply, если вы можете выполнить ту же работу используя другие функции (они часто быстрее). Например, если вы хотите округлить столбец ‘c’ до целых чисел, выполните округление (df [‘c’], 0) вместо использования функции apply.

value counts

Это команда для проверки распределения значений. Например, если вы хотите проверить возможные значения и частоту для каждого отдельного значения в столбце «c», вы можете применить

df[‘c’].value_counts()

Есть несколько полезных приемов / функций:
A. normalize = True : если вы хотите проверить частоту вместо подсчетов.
B. dropna = False : если вы хотите включить пропущенные значения в статистику.
C. sort = False : показать статистику, отсортированную по значениям, а не по количеству.

D. df[‘c].value_counts().reset_index().: если вы хотите преобразовать таблицу статистики в датафрейм Pandas и управлять ими.

количество пропущенных значений

При построении моделей может потребоваться исключить строку со слишком большим количеством пропущенных значений / строки со всеми пропущенными значениями. Вы можете использовать .isnull () и .sum () для подсчета количества пропущенных значений в указанных столбцах.

import pandas as pd
import numpy as np

df = pd.DataFrame(< ‘id’: [1,2,3], ‘c1’:[0,0,np.nan], ‘c2’: [np.nan,1,1]>)
df = df[[‘id’, ‘c1’, ‘c2’]]
df[‘num_nulls’] = df[[‘c1’, ‘c2’]].isnull().sum(axis=1)
df.head()

выбрать строки с конкретными идентификаторами

В SQL мы можем сделать это, используя SELECT * FROM… WHERE ID в («A001», «C022»,…), чтобы получить записи с конкретными идентификаторами. Если вы хотите сделать то же самое с pandas, вы можете использовать:

df_filter = df ['ID']. isin (['A001', 'C022', . ]) 
df [df_filter]

Percentile groups

Допустим, у вас есть столбец с числовыми значениями, и вы хотите классифицировать значения в этом столбце по группам, скажем, топ 5% в группу 1, 5–20% в группу 2, 20–50% в группу 3, нижние 50% в группу 4. Конечно, вы можете сделать это с помощью pandas.cut, но мы бы хотели представить другую функцию:

import numpy as np
cut_points = [np.percentile(df[‘c’], i) for i in [50, 80, 95]]
df[‘group’] = 1
for i in range(3):
df[‘group’] = df[‘group’] + (df[‘c’] < cut_points[i])
# or Которая быстро запускается (не применяется функция apply).

to_csv

Опять-таки, это команда, которую используют все. Отметим пару полезных приемов. Первый:
print(df[:5].to_csv())

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

Еще один прием касается смешанных вместе целых чисел и пропущенных значений. Если столбец содержит как пропущенные значения, так и целые числа, тип данных по-прежнему будет float, а не int. Когда вы экспортируете таблицу, вы можете добавить float_format = '%. 0f', чтобы округлить все числа типа float до целых чисел. Используйте этот прием, если вам нужны только целочисленные выходные данные для всех столбцов – так вы избавитесь от всех назойливых нулей ‘.0’ .

Формат таблиц в pandas

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

Например, в excel для этого используется условное форматирование и спарклайны. А в этой статье мы посмотрим как визуализировать данные с помощью Python и библиотеки pandas : будем использовать свойства DataFrame.style и Options and settings .

Настраиваем базовую визуализацию

Импортируем библиотеки: pandas для работы с данными и seaborn для загрузки классического набора данных penguins :

import pandas as pd import seaborn as sns

С помощью pd.set_option настроим вывод так чтобы:

  • количество строк в таблице было не больше 5;
  • текст в ячейке отражался полностью вне зависимости от длины (это удобно, если в ячейке длинный заголовок или URL, которые хочется посмотреть);
  • все числа отражались с двумя знаками после запятой;
pd.set_option('max_rows', 5) pd.set_option('display.max_colwidth', None) pd.set_option('display.float_format', ''.format)

Прочитаем и посмотрим датафрейм.

penguins = sns.load_dataset(‘penguins’) penguins

image

Если нужно вернуть настройки к дефолтным, используем pd.reset_option . Например, так, если хотим обновить все настройки разом:

pd.reset_option('all')

Полный список свойств set_option .

Настраиваем отображение данных в таблицах

Формат чисел, пропуски и регистр

У датафреймов в pandas есть свойство DataFrame.style , которое меняет отображение содержимого ячеек по условию для строк или столбцов.

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

(penguins .head(5) .style .format('', na_rep='-') .format() )

image

У нас тут всё про пингвинов, но в данные о ценах, можно добавить знак ₽ перед числом таким образом:

(df .style .format('>) )

Выделение цветом (минимум, максимум, пропуски)

Функции для поиска минимального и максимального значений не работают с текстовыми полями, поэтому заранее выделим столбцы, для которых они будут применяться, в отдельный список. Этот список будем передавать в параметр subset .

numeric_columns = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']

Подсветим минимум, максимум и пустые ячейки и выведем первые 5 строк датафрейма.

(penguins .head(5) .style .format('', na_rep='-') .format() .highlight_null(null_color='lightgrey') .highlight_max(color='yellowgreen', subset=numeric_columns) .highlight_min(color='coral', subset=numeric_columns) )

image

Наглядно видно, что в этих 5ти строках самый длинный клюв у пингвина в строке с индексом 2 и у него (неё!) же самые длинные плавники и самый маленький вес.

Усложним ещё немного: посмотрим на разброс длины плавников пингвинов-девочек вида Adelie.

Bar chart в таблице

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

adelie_female = (penguins[(penguins['species'] == 'Adelie') & (penguins['sex'] == 'FEMALE')] .copy() ) adelie_female['flipper_l_var'] = ((adelie_female['flipper_length_mm']- adelie_female['flipper_length_mm'].mean()).round())

К форматированию числовых значений, пропусков и регистра добавляем формат для столбца 'flipper_l_var' . Задаём:

  • группу столбцов ( subset ), для которых будем строить график;
  • выравнивание ( align ): mid — так как мы ожидаем, что значения будут как положительные, так и отрицательные. Подробнее про другие параметры выравнивания можно посмотреть тут;
  • цвет ( color ). В нашем случае 2 цвета: для отрицательных и положительных значений;
  • границы ( vmin , vmax ).

Отдельно с помощью set_properties пропишем, что значения в столбце 'flipper_l_var' должны стоять в центре ячейки.

(adelie_female .head(5) .style .format('', na_rep='-') .format() .bar(subset=['flipper_l_var'], align='mid', color=['coral', 'yellowgreen'], vmin=adelie_female['flipper_l_var'].min(), vmax=adelie_female['flipper_l_var'].max() ) .set_properties(**, subset='flipper_l_var') )

image

Heatmap в таблице

Иногда очень удобно подсветить все значения в таблице с помощью градиента. Например, когда нужно сравнить сгруппированные данные.

Посчитаем количество пингвинов разных видов и средние значения массы, длин плавников и клюва в зависимости от вида.

species_stat=(penguins .groupby('species') .agg(penguins_count=('species','count'), mean_bill_length=('bill_length_mm', 'mean'), mean_bill_depth=('bill_depth_mm', 'mean'), mean_flipper_length=('flipper_length_mm', 'mean'), mean_body_mass=('body_mass_g', 'mean'), ) )

image

О трех видах пингвинов можно сделать выводы и по этой таблице, но если значений становится чуть больше, хочется сразу заняться чем-то более полезным, чем разглядывать ряды чисел.

Исправим это. Потому что, ну что может быть полезнее и веселее разглядывания чисел?! И если вы думаете по-другому, я не знаю, зачем вы дочитали до этого момента.

(species_stat .T .style .format("") .background_gradient(cmap='Blues', axis=1) )

image

Транспонируем таблицу — так нагляднее сравнение между видами и применяем метод background_gradient со следующими параметрами:

  • цветовая карта( cmap ): Blues . Это одна из дефолтных карт;
  • сравнение по строкам ( axis=1 ).

Вывод

Форматирование таблиц в pandas с помощью DataFrame.style и Options and settings упрощает жизнь, ну или как минимум улучшает читабельность кода и отчетов. Но обработку типов данных, пропусков и регистра лучше, конечно, проводить осознанно ещё до этапа визуализации.

Дополнительно можно разобраться с:

  • Экспортом в excel;
  • Собственными функциями для условного форматирования. Мы использовали встроенные функции highlight_max , highlight_min и highlight_null , но для более изощрённых условий можно написать свою;
  • Такими библиотеками как sparklines и PrettyPandas .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *