Визуализация визуализации интерактивной визуализации гистограммы

У меня есть df, который выглядит так:

df.head()
Out[1]:
        A   B   C
city0   40  12  73
city1   65  56  10
city2   77  58  71
city3   89  53  49
city4   33  98  90

Пример df может быть создан с помощью следующего кода:

df = pd.DataFrame(np.random.randint(100,size=(1000000,3)), columns=list('ABC'))

indx = ['city'+str(x) for x in range(0,1000000)]
df.index = indx

Что я хочу сделать:

a) определить соответствующие длины ковша гистограммы для столбца A и присвоить каждому городу ведро для столбца A

b) определить соответствующие длины ковша гистограммы для столбца B и присвоить каждому городу ведро для столбца B

Может быть, результирующий df будет выглядеть (или есть ли встроенный способ в pandas?)

    df.head()
    Out[1]:
            A   B   C  Abkt Bbkt
    city0   40  12  73  2  1
    city1   65  56  10  4  3
    city2   77  58  71  4  3
    city3   89  53  49  5  3
    city4   33  98  90  2  5

Где Abkt и Bbkt являются идентификаторами ведра гистограммы:

1-20 = 1
21-40 = 2
41-60 = 3
61-80 = 4
81-100 = 5

В конечном счете, я хочу лучше понять поведение каждого города в отношении столбцов A, B и C и отвечать на такие вопросы, как:

a) Как выглядит распределение столбца A (или B) - то есть, какие ведра наиболее/наименее населены.

b) Условный на конкретном срезе/ведре столбца A, что выглядит распределение столбца B - то есть, какие ведра наиболее/наименее заполнены.

c) Условный на конкретном сегменте/ведре столбцов A и B, как выглядит поведение C.

В идеале я хочу иметь возможность визуализировать данные (карты тепла, идентификаторы регионов и т.д.). Я относительный новичок pandas/python и не знаю, что можно развивать.

Если сообщество SO может любезно предоставить примеры кода, как я могу делать то, что я хочу (или лучший подход, если есть лучшие методы pandas/numpy/scipy), я был бы благодарен.

Кроме того, любые указатели на ресурсы, которые могут помочь мне лучше суммировать/нарезать/копировать мои данные и быть в состоянии визуализировать на промежуточных этапах по мере продолжения моего анализа.

UPDATE:

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

Я пробовал:

1) df.hist()

ValueError: The first argument of bincount must be non-negative

2) df[['A']].hist(bins=10,range=(0,10))

array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000000A2350615C0>]], dtype=object)

Разве не #2, чтобы показать график? вместо создания объекта, который не отображается? Я использую jupyter notebook.

Есть ли что-то, что мне нужно для включения/включения в jupyter notebook для рендеринга объектов гистограммы?

UPDATE2:

Я решил проблему рендеринга: в ноутбуке Ipython, Pandas не ссылается на график, который я пытаюсь построить.

Update3:

В соответствии с предложениями комментариев я начал просматривать pandas визуализация, bokeh и seaborn. Однако я не уверен, как я могу создать связи между сюжетами.

Допустим, что у меня 10 переменных. Я хочу исследовать их, но поскольку 10 - это большое количество, чтобы изучить сразу, скажем, я хочу исследовать 5 в любой момент времени (r, s, t, u, v).

Если я хочу, чтобы интерактивный гексбин с графиком предельных распределений рассматривал связь между r и s, как я также вижу распределение t, u и v для выбранных интерактивных областей/срезов r & s (полигонов).

Я нашел гексбин с маргинальным распределением здесь hexbin plot:

Но:

1) Как сделать это интерактивным (разрешить выбор полигонов)

2) Как связать выбор региона r и s с другими графиками, например 3 графика гистограммы t, u и v (или любой другой тип графика).

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

Ответ 1

Вот новое решение, использующее bokeh и HoloViews. Он должен немного реагировать на интерактивную часть.

Я стараюсь помнить, что простота красива, когда дело доходит до dataviz.

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

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

import pandas as pd
import numpy as np
from faker import Faker

def generate_random_dataset(city_number, 
                        list_identifier,
                        labels,
                        bins,
                        city_location='en_US'):

    fake = Faker(locale=city_location)

    df = pd.DataFrame(data=np.random.uniform(0, 100, len(list_identifier)]), 
                      index=[fake.city() for _ in range(city_number)], 
                      columns=list_identifier)

    for name in list_identifier:
        df[name + 'bkt'] =  pd.Series(pd.cut(df[name], bins, labels=labels))

    return df

list_identifier=list('ABC')
labels = ['Low', 'Medium', 'Average', 'Good', 'Great']
bins = np.array([-1, 20, 40, 60, 80, 101])

df = generate_random_dataset(30, list_identifier, labels, bins)

df.head()

будет выводиться: df

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

from bokeh.charts import Bar, output_file, show
from bokeh.layouts import column

bar = []
for name in list_identifier:
    bar.append(Bar(df, label='index', values=name, stack=name+'bkt',
               title="percentage of " + name, legend='top_left', plot_width=1024))

output_file('cities.html')

show(column(bar))

Создает новую html-страницу (города), содержащую графики. Обратите внимание, что все графики, сгенерированные с помощью bokeh, являются интерактивными.

graphA

graphB

bokeh не может первоначально построить гексбин. Однако HoloViews может. Таким образом, он позволяет рисовать интерактивные сюжеты whitin ipython notebook.

Синтаксис довольно прост, вам просто нужна матрица с двумя столбцами и вызовите метод hist:

import holoviews as hv
hv.notebook_extension('bokeh')

df = generate_random_dataset(1000, list_identifier, list(range(5)), 5)

points = hv.Points(np.column_stack((df.A, df.B)))
points.hist(num_bins=5, dimension=['x', 'y'])

перераспределение A и B

Чтобы сравнить с решением @piRSquared, я украл немного кода (спасибо вам, чтобы показать данные с некоторой корреляцией:

mean, cov = [0, 1], [(1, .5), (.5, 1)]
data = np.random.multivariate_normal(mean, cov, 100000)
df = pd.DataFrame(data, columns=["A", "B"])

df.index = df.index.to_series().astype(str).radd('city')

df_ = pd.cut(df[['A', 'B']].stack(), 30, labels=list(range(30))).unstack()
df_.columns = df_.columns.to_series() + 'bkt'

points = hv.Points(np.column_stack((df_.Abkt, df_.Bbkt)))
points.hist(num_bins=5, dimension=['x', 'y'])

средняя ковариация

Пожалуйста, рассмотрите HoloViews tutorial.

Ответ 2

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

Самый чистый способ, который я могу сделать, это stack в один series, затем использовать pd.cut

Учитывая ваш образец df

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

df_ = pd.cut(df[['A', 'B']].stack(), 5, labels=list(range(5))).unstack()
df_.columns = df_.columns.to_series() + 'bkt'
pd.concat([df, df_], axis=1)

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


Давайте построим лучший пример и посмотрим на визуализацию с помощью seaborn

df = pd.DataFrame(dict(A=(np.random.randn(10000) * 100 + 20).astype(int),
                       B=(np.random.randn(10000) * 100 - 20).astype(int)))

import seaborn as sns

df.index = df.index.to_series().astype(str).radd('city')

df_ = pd.cut(df[['A', 'B']].stack(), 30, labels=list(range(30))).unstack()
df_.columns = df_.columns.to_series() + 'bkt'

sns.jointplot(x=df_.Abkt, y=df_.Bbkt, kind="scatter", color="k")

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


Или как насчет некоторых данных с некоторой корреляцией

mean, cov = [0, 1], [(1, .5), (.5, 1)]
data = np.random.multivariate_normal(mean, cov, 100000)
df = pd.DataFrame(data, columns=["A", "B"])

df.index = df.index.to_series().astype(str).radd('city')

df_ = pd.cut(df[['A', 'B']].stack(), 30, labels=list(range(30))).unstack()
df_.columns = df_.columns.to_series() + 'bkt'

sns.jointplot(x=df_.Abkt, y=df_.Bbkt, kind="scatter", color="k")

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


Интерактивный bokeh

Без слишком сложного

from bokeh.io import show, output_notebook, output_file

from bokeh.plotting import figure
from bokeh.layouts import row, column
from bokeh.models import ColumnDataSource, Select, CustomJS

output_notebook()

# generate random data
flips = np.random.choice((1, -1), (5, 5))
flips = np.tril(flips, -1) + np.triu(flips, 1) + np.eye(flips.shape[0])

half = np.ones((5, 5)) / 2
cov = (half + np.diag(np.diag(half))) * flips
mean = np.zeros(5)

data = np.random.multivariate_normal(mean, cov, 10000)
df = pd.DataFrame(data, columns=list('ABCDE'))

df.index = df.index.to_series().astype(str).radd('city')

# Stack and cut to get dependent relationships
b = 20
df_ = pd.cut(df.stack(), b, labels=list(range(b))).unstack()

# assign default columns x and y.  These will be the columns I set bokeh to read
df_[['x', 'y']] = df_.loc[:, ['A', 'B']]

source = ColumnDataSource(data=df_)

tools = 'box_select,pan,box_zoom,wheel_zoom,reset,resize,save'

p = figure(plot_width=600, plot_height=300)
p.circle('x', 'y', source=source, fill_color='olive', line_color='black', alpha=.5)

def gcb(like, n):
    code = """
    var data = source.get('data');
    var f = cb_obj.get('value');
    data['{0}{1}'] = data[f];
    source.trigger('change');
    """
    return CustomJS(args=dict(source=source), code=code.format(like, n))

xcb = CustomJS(
    args=dict(source=source),
    code="""
    var data = source.get('data');
    var colm = cb_obj.get('value');
    data['x'] = data[colm];
    source.trigger('change');
    """
)

ycb = CustomJS(
    args=dict(source=source),
    code="""
    var data = source.get('data');
    var colm = cb_obj.get('value');
    data['y'] = data[colm];
    source.trigger('change');
    """
)

options = list('ABCDE')
x_select = Select(options=options, callback=xcb, value='A')
y_select = Select(options=options, callback=ycb, value='B')


show(column(p, row(x_select, y_select)))

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

Ответ 3

Как новичок с недостаточной репутацией, я не могу комментировать, поэтому я ставлю это здесь как "ответ", хотя его нельзя рассматривать как один; это лишь некоторые неполные предложения в том же духе, что и комментарии.

Наряду с другими мне нравится seaborn, хотя я не уверен, что эти сюжеты являются интерактивными в том виде, в котором вы ищете. Хотя я не использовал bokeh, я понимаю, что он обеспечивает больше возможностей интерактивности, но независимо от пакета, поскольку вы переходите за пределы 3 и 4 переменных, вы можете так сильно влизать в одно (семейство) графики.

Как и в вашей таблице, вышеупомянутый df.hist() (lanery) является хорошим началом. После того, как у вас есть эти бункеры, вы можете играть с чрезвычайно мощной df.groupby() функцией. Я использую pandas уже два года, и эта функция STILL дует мне в голову. Хотя это и не интерактивно, это определенно поможет вам нарезать и нарезать ваши данные по своему усмотрению.