Панды, плотные тепловые карты и матрица

#python-3.x #pandas #dataframe #plotly #plotly-python

#python-3.x #панды #фрейм данных #сюжетно #plotly-python

Вопрос:

Я использую python 3.8, plotly 4.14.1, pandas1.2.0

Я не могу понять, как разделить мои данные в pandas и назначить данные счетчикам, чтобы я мог обновить тепловую карту.

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

Жесткое кодирование данных в dataframe, и оно работает так, как ожидалось

ниже с рисунком фабрики

 gross_data=[[0,1,2,6,3], [0,7,18,12,6], [6,10,43,44,7], [3,15,29,46,18], [5,14,26,22,21]]

x=['Minor [Very Low]<br>1', 'Important [Low]<br>2', 'Significant [Moderate]<br>3', 'Major [High]<br>4', 'Critical [Very High]<br>5']
y=['Very Remote<br>1', 'Remote<br>2', 'Unlikely<br>3', 'Possible<br>4', 'Highly Possible<br>5']

fig = ff.create_annotated_heatmap(gross_data, x=x, y=y, colorscale='Magma')
fig['layout']['xaxis']['side'] = 'bottom'
fig.show()
 

Тепловая карта с аннотированной фабрикой Plotly Figfure
введите описание изображения здесь

или сделать это с помощью plotly express

 gross_data=[[0,1,2,6,3], [0,7,18,12,6], [6,10,43,44,7], [3,15,29,46,18], [5,14,26,22,21]]

fig = px.imshow(gross_data,
                labels=dict(x="Impact", y="Probability", color="Number of Risks"),
                x=['Minor [Very Low]', 'Important [Low]', 'Significant [Moderate]', 'Major [High]', 'Critical [Very High]'],
                y=['Very Remote', 'Remote', 'Unlikely', 'Possible', 'Highly Possible']
               )
fig.update_xaxes(side="bottom")

fig.show()
 

Плотная Тепловая карта
введите описание изображения здесь

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

Я использую pandas для чтения примерно 1000 строк данных Excel, которые были заполнены человеком в виде формы со всеми возникающими ошибками. Я привел их в порядок и очистил данные.

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

 for X in df[gross_impact]:
    for y in df[gross_likelihood]:
        if (x == 1) amp; (y == 1):
            increment a counter associated with cell x1y1
       elif (x == 2) amp; (y == 1):
            increment a counter associated with cell x2y1
       elif (x == 3) amp; (y == 1):
            increment a counter associated with cell x3y1
       elif (x == 4) amp; (y == 1):
            increment a counter associated with cell x4y1
       elif (x == 4) amp; (y == 1):
            increment a counter associated with cell x5y1
       elif (x == 1) amp; (y == 2):
            increment a counter associated with cell x1y2
       elif (x == 2) amp; (y == 2):
            increment a counter associated with cell x2y2
      .....
      .....
      elif (x == 5) amp; (y == 5):
        increment a counter associated with cell x5y5
 

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

Я просто не могу понять, как мне это сделать. Я прочитал пару вопросов stack exchange, но они не касались моего запроса. Я исследовал всю сеть в поисках матриц рисков, но это возвращается к c или финансовым данным, которые не выглядят применимыми.

Мой фрейм данных содержит около 30 полей, но уникальной ссылкой является risk_id. Моими полями, которые я умножаю друг на друга, являются risk_impact и risk_likelability. и я мог бы сортировать по risk_id и business_unit

Я должен различать 1 x 3 и 3 x 1, поскольку это относится к двум разным ячейкам, подсчет должен вестись снизу слева направо, так что 1 x 3 — столбец 1, строка 3. 3 x 1 — столбец 3 строка 1

Надеюсь, это понятно. если бы я точно знал, о чем просить, я, возможно, сделал бы это

Буду очень признателен за любую помощь в решении этой проблемы.

вот пример данных, которые у меня есть в моем хранилище данных

 import pandas as pf

# Our data to be loaded into the data frame
data = {'risk_id': ['AP-P01-R01', 'AP-P02-R02', 'AP-P03-R03', 'AP-P01-R04', 'BP-P01-R01', 'BP-P01-R02', 'BP-P01-R03', 'BP-P01-R04', 'BP-P01-R05', 'BP-P01-R06', 'BP-P01-R07', 'CP-P01-R01', 'CP-P01-R02', 'CP-P01-R03', 'CP-P01-R04', 'CP-P01-R05', 'CP-P01-R06', 'CP-P01-R07', 'CP-P01-R08'],
        'gross_impact': [4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 3, 3, 4, 4, 2, 3, 5, 3, 2],
        'gross_likelihood': [3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 2, 3, 3, 3, 3, 4, 4, 5, 3],
        'business_unit': ['Accounts Payable', 'Accounts Payable', 'Accounts Payable', 'Accounts Payable', 'British Petroleum', 'British Petroleum', 'British Petroleum', 'British Petroleum', 'British Petroleum', 'British Petroleum', 'British Petroleum', 'Client Profile', 'Client Profile', 'Client Profile', 'Client Profile', 'Client Profile', 'Client Profile', 'Client Profile', 'Client Profile']
        }

 

Все это загружается нормально

Загруженный фрейм данных

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

Ошибка IndexError: массивы, используемые в качестве индексов, должны иметь целочисленный (или логический) тип

Ошибка появляется, когда я запускаю код, и его следующая строка выдает ошибку

 heatmap[counts[:,1]-1, counts[:,0]-1] = counts[:,2]
 

полный код, который я использую, таков

 df = raca_df[['risk_id', 'gross_impact','gross_likelihood', 'business_unit']].dropna()
counts = df.groupby(['gross_impact','gross_likelihood']).apply(len).reset_index().values

heatmap = np.zeros((np.max(5), np.max(5)))
#heatmap = np.zeros((np.max(df['gross_impact']), np.max(df['gross_likelihood'])))
heatmap[counts[:,1]-1, counts[:,0]-1] = counts[:,2]

import plotly.figure_factory as ff
fig = ff.create_annotated_heatmap(heatmap)
fig['layout']['xaxis']['side'] = 'bottom'
fig.show()
 

После получения запроса о том, как я создал raca df, я быстро raca_df.info указал на мою проблему. Это оказалось проблемой с моим исходным фреймом данных raca_df и типом столбца float64. У меня также было несколько пустых записей в столбце, так что это не позволило бы мне изменить там тип столбца.

Мне пришлось создать новый фрейм данных из raca_df с воображаемым именем df, и я изменил типы столбцов там, используя цикл и astype(‘int’)

 df = raca_df[['risk_id', 'gross_impact','gross_likelihood', 'business_unit']].dropna()

for item in ['gross_impact','gross_likelihood', 'net_impact', 'net_likelihood']:
    raca_df[item] = raca_df[item].astype('int')
 

Комментарии:

1. привет. пожалуйста, приведите пример ваших данных

2. Добавлены примерные данные

3. как вы определили raca_df ?

4. Эй, спасибо за это. Я просто прокомментировал этот вопрос. Теперь я исправил эту проблему. моими исходными столбцами были float62, но я не мог изменить их на int, так как в столбцах были пустые значения. когда я создал фрейм данных df, я затем удалил значения blankel через .dropna Затем я смог изменить тип столбца, и теперь все работает отлично. еще раз спасибо, что нашли время указать мне правильное направление

Ответ №1:

вы можете сгруппировать по воздействию и вероятности и использовать groupsize для получения интенсивности вашей тепловой карты.:

 counts = df.groupby(['gross_impact','gross_likelihood']).apply(len).reset_index().values

# then, you can initialise an empty heatmap and use fancy indexing to populate it:    
heatmap = np.zeros((np.max(df['gross_impact']), np.max(df['gross_likelihood'])))
heatmap[counts[:,0]-1, counts[:,1]-1] = counts[:,2]

# and finally plot it
import plotly.figure_factory as ff
fig = ff.create_annotated_heatmap(heatmap)
fig.show()
 

Редактировать:

для отдельных бизнес-подразделений вы можете запустить один и тот же код с помощью любой из этих настроек:

 # for a single business unit
counts = df[df['business_unit']=='Accounts Payable'].groupby(['gross_impact','gross_likelihood']).apply(len).reset_index().values

# and then the remaining code


# for all units, you can loop:
for business_unit in set(df['business unit']):
    counts = df[df['business unit']==business_unit].groupby(['gross_impact','gross_likelihood']).apply(len).reset_index().values
    
    # and then the remaining code   
 

Комментарии:

1. отлично! дайте мне знать, если что-то еще неясно

2. Привет, извращенный. Спасибо за то, что это хорошо работает. Я поиграл с этим и думаю, что понимаю большую часть этого. Я изменил вторую строку на «тепловая карта = np.zeros ((np.max (5), np.max (5)))», поскольку существовала вероятность того, что не будет никаких воздействий и вероятностей 5, и, следовательно, матрица может уменьшиться. Можете ли вы объяснить индексацию? Я поиграл с ним, изменяя данные, чтобы увидеть эффект, но, взглянув на графическую фигуру create_annotated_heatmap, я не вижу, как отображается матрица. мы просто сопоставляем значения, а тепловая карта заботится о x и y?

3. Можете ли вы также указать мне, как я мог бы выделить подмножество для тепловой карты одного бизнес-подразделения?

4. если вы посмотрите counts , вы увидите, что в нем 3 столбца. Они происходят, соответственно, из gross_impact , gross_likelihood и groupsize . gross_impact интерпретируется как индекс строки, gross_likelihood как индекс столбца, а присваиваемое значение — это размер группы. -1 исправляет тот факт, что индексация python начинается с 0.

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