Создание графиков разметки matplotlib из dataframes в Python pandas
Каков наилучший способ сделать серию диаграмм рассеяния, используя matplotlib
из pandas
dataframe в Python?
Например, если у меня есть dataframe df
, который имеет некоторые столбцы, представляющие интерес, я, как правило, преобразовываю все в массивы:
import matplotlib.pylab as plt
# df is a DataFrame: fetch col1 and col2
# and drop na rows if any of the columns are NA
mydata = df[["col1", "col2"]].dropna(how="any")
# Now plot with matplotlib
vals = mydata.values
plt.scatter(vals[:, 0], vals[:, 1])
Проблема с преобразованием всего массива перед построением заключается в том, что он заставляет вас вырваться из фреймов данных.
Рассмотрим эти два случая использования, когда полный график данных необходим для построения:
-
Например, если вы хотите теперь просмотреть все значения col3
для соответствующих значений, которые вы построили при вызове scatter
, и покрасить каждую точку (или размер) ее стоимость? Вам нужно будет вернуться назад, вытащить значения не-na col1,col2
и проверить, что их соответствующие значения.
Есть ли способ построения, сохраняя данные? Например:
mydata = df.dropna(how="any", subset=["col1", "col2"])
# plot a scatter of col1 by col2, with sizes according to col3
scatter(mydata(["col1", "col2"]), s=mydata["col3"])
-
Аналогично, представьте, что вы хотите фильтровать или окрашивать каждую точку по-разному в зависимости от значений некоторых ее столбцов. Например. что, если вы хотите автоматически строить метки точек, которые встречаются с определенным обрезанием на col1, col2
вместе с ними (где метки хранятся в другом столбце df), или покрасить эти точки по-разному, как люди делают с кадрами данных в R Например:
mydata = df.dropna(how="any", subset=["col1", "col2"])
myscatter = scatter(mydata[["col1", "col2"]], s=1)
# Plot in red, with smaller size, all the points that
# have a col2 value greater than 0.5
myscatter.replot(mydata["col2"] > 0.5, color="red", s=0.5)
Как это можно сделать?
РЕДАКТИРОВАТЬ Ответ экипажу:
Вы говорите, что наилучшим способом является построение каждого условия (например, subset_a
, subset_b
) отдельно. Что делать, если у вас много условий, например. вы хотите разбить рассеиватели на 4 типа точек или даже больше, построив каждый в другой форме/цвете. Как вы можете элегантно применять условия a, b, c и т.д. И убедиться, что вы затем задумали "остальное" (вещи не в любом из этих условий) в качестве последнего шага?
Аналогично, в вашем примере, где вы рисуете col1,col2
по-разному на основе col3
, что, если есть значения NA, которые нарушают связь между col1,col2,col3
? Например, если вы хотите построить все значения col2
на основе их значений col3
, но некоторые строки имеют значение NA в col1
или col3
, заставляя вас сначала использовать dropna
. Итак, вы бы сделали:
mydata = df.dropna(how="any", subset=["col1", "col2", "col3")
тогда вы можете построить с помощью mydata
, как вы показываете, - разметку разброса между col1,col2
с использованием значений col3
. Но mydata
будет отсутствовать некоторые точки, которые имеют значения для col1,col2
, но являются NA для col3
, и они все еще должны быть построены... так как бы вы в основном заложили "остальную" информацию, т.е. точки, которые не находятся в отфильтрованном наборе mydata
?
Ответы
Ответ 1
Попробуйте передать столбцы DataFrame
непосредственно в matplotlib, как в приведенных ниже примерах, вместо того, чтобы извлекать их как массивы numpy.
df = pd.DataFrame(np.random.randn(10,2), columns=['col1','col2'])
df['col3'] = np.arange(len(df))**2 * 100 + 100
In [5]: df
Out[5]:
col1 col2 col3
0 -1.000075 -0.759910 100
1 0.510382 0.972615 200
2 1.872067 -0.731010 500
3 0.131612 1.075142 1000
4 1.497820 0.237024 1700
Изменение размера точки разброса на основе другого столбца
plt.scatter(df.col1, df.col2, s=df.col3)
# OR (with pandas 0.13 and up)
df.plot(kind='scatter', x='col1', y='col2', s=df.col3)
![enter image description here]()
Изменение цвета точки разброса на основе другого столбца
colors = np.where(df.col3 > 300, 'r', 'k')
plt.scatter(df.col1, df.col2, s=120, c=colors)
# OR (with pandas 0.13 and up)
df.plot(kind='scatter', x='col1', y='col2', s=120, c=colors)
![enter image description here]()
График рассеяния с легендой
Однако самый простой способ создать график рассеяния с легендой - вызвать plt.scatter
один раз для каждого типа точки.
cond = df.col3 > 300
subset_a = df[cond].dropna()
subset_b = df[~cond].dropna()
plt.scatter(subset_a.col1, subset_a.col2, s=120, c='b', label='col3 > 300')
plt.scatter(subset_b.col1, subset_b.col2, s=60, c='r', label='col3 <= 300')
plt.legend()
![enter image description here]()
Update
Из того, что я могу сказать, matplotlib просто пропускает точки с координатами NA x/y или настройками стиля NA (например, цвет/размер). Чтобы найти точки, пропущенные из-за NA, попробуйте метод isnull
: df[df.col3.isnull()]
Чтобы разбить список точек на многие типы, посмотрите numpy select
, который является векторизованным if-then-else реализации и принимает необязательное значение по умолчанию. Например:
df['subset'] = np.select([df.col3 < 150, df.col3 < 400, df.col3 < 600],
[0, 1, 2], -1)
for color, label in zip('bgrm', [0, 1, 2, -1]):
subset = df[df.subset == label]
plt.scatter(subset.col1, subset.col2, s=120, c=color, label=str(label))
plt.legend()
![enter image description here]()
Ответ 2
В Garrett мало что можно добавить, но pandas также имеет метод scatter
. Используя это, это так же просто, как
df = pd.DataFrame(np.random.randn(10,2), columns=['col1','col2'])
df['col3'] = np.arange(len(df))**2 * 100 + 100
df.plot.scatter('col1', 'col2', df['col3'])
![размер графика в col3 до col1-col2]()
Ответ 3
Я рекомендую использовать альтернативный метод с использованием seaborn
который является более мощным инструментом для построения данных. Вы можете использовать seaborn scatterplot
и определить столб 3 как hue
и size
.
Рабочий код:
import pandas as pd
import seaborn as sns
import numpy as np
#creating sample data
sample_data={'col_name_1':np.random.rand(20),
'col_name_2': np.random.rand(20),'col_name_3': np.arange(20)*100}
df= pd.DataFrame(sample_data)
sns.scatterplot(x="col_name_1", y="col_name_2", data=df, hue="col_name_3",size="col_name_3")
![enter image description here]()