Подтвердить что ты не робот

Как отформатировать 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))
4b9b3361

Ответ 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 для примера.