Стиль данных Pandas - цветные столбцы по категориям - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть следующий фрейм данных:

# define categorical column.
grps = pd.DataFrame(['a', 'a', 'a', 'b', 'b', 'b']) 

# generate dataframe.
df = pd.DataFrame(np.random.randn(18).reshape(6, 3))

# concatenate categorical column and dataframe.
df = pd.concat([grps, df], axis = 1)

# Assign column headers.
df.columns = ['group', 1, 2, 3]

Обычно мои фреймы данных могут содержать изменяющиеся номера уровней для столбца категории, т. Е. 'A', 'b', 'c', 'd'. ..et c.

Затем я могу сгенерировать стиль данных pandas, используя метод .bar(), а затем записать в файл html:

# style the dataframe.
style_df = (df.style.bar(align = 'zero', color = '#FFA07A'))

# write styled dataframe to html.
df_html = style_df.hide_index().render()
with open("style_df.html","w") as fp:
    fp.write(df_html)

Как мне раскрасить столбцы для каждого числового столбца по столбцу категории группы?

Я пытался использовать pd.IndexSlice для создания подмножеств основного фрейма данных по группам, а затем передавать их методу .bar(), как в Pandas style.bar, в зависимости от условия . Однако я получаю следующую ошибку: IndexingError: Too many indexers. Даже если это сработало, это не идеально, поскольку мне нужно было бы вручную добавлять последовательные методы .bar() в стайлер. В идеале я хотел бы, чтобы код реагировал на разные уровни группы для любого заданного фрейма данных.

Я думаю, что условное форматирование с использованием встроенного метода Styler.apply может быть лучшим вариантом, но не имеет ничего для работы на основе приведенных здесь примеров: https://pandas.pydata.org/pandas-docs/stable/user_guide/style.html. Все они основаны на форматировании фона ячеек или самих значений.

Любые указатели будут с благодарностью.

1 Ответ

0 голосов
/ 01 марта 2020

Я нашел способ адаптировать код из этого поста: Как установить ячейку, а не столбец или строку в кадре данных с цветом?

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

Мне нужно было определить функцию, которая выполняет этот процесс, и затем я могу применить ее к таблице в методе стилера pandas.

import pandas as pd
import numpy as np

# define categorical column.
grps = pd.DataFrame(['a', 'a', 'a', 'b', 'b', 'b']) 

# generate dataframe.
df = pd.DataFrame(np.random.randn(18).reshape(6, 3))

# concatenate categorical column and dataframe.
df = pd.concat([grps, df], axis = 1)

# Assign column headers.
df.columns = ['group', 1, 2, 3]

Функция для выделения строк переменной класса.

def highlight_rows(x):
    """ Function to apply alternating colour scheme to table cells by rows
    according to groups. 

    Parameters:
    x: dataframe to be styled.

    Returns:
    Styled dataframe

    """
    # ----------------------------------------------------------------------- #
    ### Set initial condition.

    # Generate copy of input dataframe. This will avoid chained indexing issues.
    df_cpy = x.copy()

    # ----------------------------------------------------------------------- #
    ### Define row index ranges per experimental group.

    # Reset numerical index in dataframe copy. Generates new column at
    # position 1 called 'index' and consisting of index positions.
    df_cpy = df_cpy.reset_index()

    # Generate dictionary of key:value pairs corresponding to 
    # grouped experimental class:index range as numerical list, respectively.
    grp_indexers_dict = dict(tuple((df_cpy.groupby('group')['index'])))

    # Generate list of series from dictionary values.
    indexers_series_lst = list(grp_indexers_dict.values())

    # Drop first column - 'index'. This is necessary to avoid 'ValueError' 
    # issue at a later stage. This is due to the extra column causing dataframe 
    # mismatching when this function is called from 'style_df()' function.
    df_cpy = df_cpy.drop('index', axis = 1)

    # ----------------------------------------------------------------------- #
    ### Initiate 'try' block.

    try:
    # Set default color as no colour.
       df_cpy.loc[:,:] = '' 

       # Set row colour by referencing elements of a list of series.
       # Each series corresponds to the numerical row index positions
       # for each group class. They therefore represent each class. 
       # They are generated dynamically from the input dataframe group column
       # in the 'style_df()' function, from which this function is called.
       # Numerical series can be used to slice a dataframe and specifically 
       # pass colour schemes to row subsets.
       # Note: 4 experimental groups defined below in order to account
       # for higher number of group levels. The idea is that these should 
       # always be in excess of total groups.

       # Group - 1.
       df_cpy.iloc[indexers_series_lst[0], ] = 'background-color: #A7CDDD'
       # Group - 2.
       df_cpy.iloc[indexers_series_lst[1], ] = 'background-color: #E3ECF8'
       # Group - 3.
       df_cpy.iloc[indexers_series_lst[2], ] = 'background-color: #A7CDDD'
       # Group - 4.
       df_cpy.iloc[indexers_series_lst[3], ] = 'background-color: #E3ECF8'

       # Return styled dataframe if total experimental classes equal
       # to total defined groups above.
       return(df_cpy)

    # ----------------------------------------------------------------------- #
    ### Initiate 'except' block.

    # Catches index error generated when there are fewer experimental
    # groups than defined in preceding 'try' block. 
    except IndexError:

       # Return styled dataframe.
       return(df_cpy)

Передача функции в стилизатор и генерация таблицы html в стиле.

# style the dataframe.
style_df = (df.style
            .bar(align = 'zero', color = '#FFA07A')
            # Call 'highlight_rows()' function to colour rows by group class.
            .apply(highlight_rows, axis=None))

# write styled dataframe to html.
df_html = style_df.hide_index().render()
with open("style_df.html","w") as fp:
    fp.write(df_html)enter code here

Хотя это хорошо работает для тип данных, с которыми я имею дело (очень не похож на go за пределами 10 групп, следовательно, имея в своем реальном коде до 10 индексаторов), не так элегантен, как функция динамически реагирует на количество групп.

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

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