Визуализация визуализации интерактивной визуализации гистограммы
У меня есть 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 дует мне в голову. Хотя это и не интерактивно, это определенно поможет вам нарезать и нарезать ваши данные по своему усмотрению.