Как отформатировать html-представление IPython Pandas dataframe?
Как я могу отформатировать html-отображение IPython pandas данных, чтобы
- правильны.
- номера имеют запятые в качестве разделителя тысяч.
- большие поплавки не имеют десятичных знаков
Я понимаю, что numpy
имеет возможность set_printoptions
, где я могу:
int_frmt:lambda x : '{:,}'.format(x)
np.set_printoptions(formatter={'int_kind':int_frmt})
и аналогичным образом для других типов данных.
Но IPython не выбирает эти параметры форматирования при отображении dataframes в html. Мне все еще нужно иметь
pd.set_option('display.notebook_repr_html', True)
но с 1, 2, 3, как указано выше.
Изменить: Ниже мое решение для 2 и 3 (не уверен, что это лучший способ), но мне все же нужно выяснить, как сделать столбцы номеров правильными.
from IPython.display import HTML
int_frmt = lambda x: '{:,}'.format(x)
float_frmt = lambda x: '{:,.0f}'.format(x) if x > 1e3 else '{:,.2f}'.format(x)
frmt_map = {np.dtype('int64'):int_frmt, np.dtype('float64'):float_frmt}
frmt = {col:frmt_map[df.dtypes[col]] for col in df.columns if df.dtypes[col] in frmt_map.keys()}
HTML(df.to_html(formatters=frmt))
Ответы
Ответ 1
HTML получает пользовательскую строку html-данных. Никто не запрещает вам передавать в теге стиль пользовательский стиль CSS для класса .dataframe
(который метод to_html
добавляет в таблицу).
Таким образом, самым простым решением было бы просто добавить стиль и объединить его с выходом df.to_html
:
style = '<style>.dataframe td { text-align: right; }</style>'
HTML( style + df.to_html( formatters=frmt ) )
Но я бы предложил определить пользовательский класс для DataFrame, так как это изменит стиль всех таблиц в вашем ноутбуке (стиль "глобальный" ).
style = '<style>.right_aligned_df td { text-align: right; }</style>'
HTML(style + df.to_html(formatters=frmt, classes='right_aligned_df'))
Вы также можете определить стиль в одной из предыдущих ячеек, а затем просто установите параметр classes
метода to_html
:
# Some cell at the begining of the notebook
In [2]: HTML('''<style>
.right_aligned_df td { text-align: right; }
.left_aligned_df td { text-align: right; }
.pink_df { background-color: pink; }
</style>''')
...
# Much later in your notebook
In [66]: HTML(df.to_html(classes='pink_df'))
Ответ 2
Этот вопрос задавали давно. Тогда pandas еще не включил pd.Styler. Он был добавлен в версию 0.17.1
.
Вот как вы могли бы использовать это для достижения желаемой цели и еще:
- Центрировать заголовок
- выравнивание по правому краю столбцов любых столбцов
- выровнять по левому краю другие столбцы.
- Добавьте форматтер для числовых столбцов, которые вы хотите
- сделать так, чтобы каждый столбец имел одинаковую ширину.
Вот некоторые примеры данных:
In [1]:
df = pd.DataFrame(np.random.rand(10,3)*2000, columns=['A','B','C'])
df['D'] = np.random.randint(0,10000,size=10)
df['TextCol'] = np.random.choice(['a','b','c'], 10)
df.dtypes
Out[1]:
A float64
B float64
C float64
D int64
TextCol object
dtype: object
Отформатируйте это с помощью df.style
:
# Construct a mask of which columns are numeric
numeric_col_mask = df.dtypes.apply(lambda d: issubclass(np.dtype(d).type, np.number))
# Dict used to center the table headers
d = dict(selector="th",
props=[('text-align', 'center')])
# Style
df.style.set_properties(subset=df.columns[numeric_col_mask], # right-align the numeric columns and set their width
**{'width':'10em', 'text-align':'right'})\
.set_properties(subset=df.columns[~numeric_col_mask], # left-align the non-numeric columns and set their width
**{'width':'10em', 'text-align':'left'})\
.format(lambda x: '{:,.0f}'.format(x) if x > 1e3 else '{:,.2f}'.format(x), # format the numeric values
subset=pd.IndexSlice[:,df.columns[numeric_col_mask]])\
.set_table_styles([d]) # center the header
![Результат с использованием pd.Styler]()
Обратите внимание, что вместо вызова .format
в столбцах подмножества вы можете установить глобальный по умолчанию pd.options.display.float_format
:
pd.options.display.float_format = lambda x: '{:,.0f}'.format(x) if x > 1e3 else '{:,.2f}'.format(x)
Ответ 3
В точке OP 2:
цифры имеют запятые как разделители тысяч
pandas (начиная с 0.20.1) не позволяет легко переопределить целочисленный формат по умолчанию. Он жестко закодирован в pandas.io.formats.format.IntArrayFormatter
(функция labmda
):
class IntArrayFormatter(GenericArrayFormatter):
def _format_strings(self):
formatter = self.formatter or (lambda x: '% d' % x)
fmt_values = [formatter(x) for x in self.values]
return fmt_values
Я предполагаю, что вы действительно спрашиваете, как вы можете переопределить формат для всех целых чисел: replace ( "monkey patch" ) IntArrayFormatter
для печати целочисленных значений с тысячами разделенных запятой следующим образом:
import pandas
class _IntArrayFormatter(pandas.io.formats.format.GenericArrayFormatter):
def _format_strings(self):
formatter = self.formatter or (lambda x: ' {:,}'.format(x))
fmt_values = [formatter(x) for x in self.values]
return fmt_values
pandas.io.formats.format.IntArrayFormatter = _IntArrayFormatter
Примечание:
- до 0.20.0, форматировщики находились в
pandas.formats.format
.
- до 0.18.1, форматировщики находились в
pandas.core.format
.
Помимо
Для поплавков вам не нужно перепрыгивать через эти обручи, так как есть параметр конфигурации для него:
display.float_format
: вызываемый должен принять число с плавающей запятой и вернуть строку с нужным форматом номера. Это используется в некоторых местах, например SeriesFormatter
. См. core.format.EngFormatter
для примера.