作者:lemonbit
from Unsplash by@Mike Enerio
翻译 |Lemon
来源 | Machine Learning Plus
23 直方密度线图 (Density Curves with Histogram)带有直方图的密度曲线汇集了两个图所传达的集体信息,因此您可以将它们放在一个图中而不是两个图中。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Draw Plot
plt.figure(figsize=(13,10), dpi= 80)
sns.distplot(df.loc[df['class'] == 'compact', 'cty'], color='dodgerblue', label='Compact', hist_kws={'alpha':.7}, kde_kws={'linewidth':3})
sns.distplot(df.loc[df['class'] == 'suv', 'cty'], color='orange', label='SUV', hist_kws={'alpha':.7}, kde_kws={'linewidth':3})
sns.distplot(df.loc[df['class'] == 'minivan', 'cty'], color='g', label='minivan', hist_kws={'alpha':.7}, kde_kws={'linewidth':3})
plt.ylim(0, 0.35)
# Decoration
plt.title('Density Plot of City Mileage by Vehicle Type', fontsize=22)
plt.legend()
plt.show()
图23
24 Joy PlotJoy Plot允许不同组的密度曲线重叠,这是一种可视化大量分组数据的彼此关系分布的好方法。 它看起来很悦目,并清楚地传达了正确的信息。 它可以使用基于 matplotlib 的 joypy 包轻松构建。 (『Python数据之道』注:需要安装 joypy 库)
# !pip install joypy
# Python数据之道 备注
import joypy
# Import Data
mpg = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Draw Plot
plt.figure(figsize=(16,10), dpi= 80)
fig, axes = joypy.joyplot(mpg, column=['hwy', 'cty'], by='class', ylim='own', figsize=(14,10))
# Decoration
plt.title('Joy Plot of City and Highway Mileage by Class', fontsize=22)
plt.show()
图24
25 分布式包点图 (Distributed Dot Plot)分布式包点图显示按组分割的点的单变量分布。 点数越暗,该区域的数据点集中度越高。 通过对中位数进行不同着色,组的真实定位立即变得明显。
图25
26 箱形图 (Box Plot)箱形图是一种可视化分布的好方法,记住中位数、第25个第45个四分位数和异常值。 但是,您需要注意解释可能会扭曲该组中包含的点数的框的大小。 因此,手动提供每个框中的观察数量可以帮助克服这个缺点。
例如,左边的前两个框具有相同大小的框,即使它们的值分别是5和47。 因此,写入该组中的观察数量是必要的。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Draw Plot
plt.figure(figsize=(13,10), dpi= 80)
sns.boxplot(x='class', y='hwy', data=df, notch=False)
# Add N Obs inside boxplot (optional)
def add_n_obs(df,group_col,y):
medians_dict = {grp[0]:grp[1][y].median() for grp in df.groupby(group_col)}
xticklabels = [x.get_text() for x in plt.gca().get_xticklabels()]
n_obs = df.groupby(group_col)[y].size().values
for (x, xticklabel), n_ob in zip(enumerate(xticklabels), n_obs):
plt.text(x, medians_dict[xticklabel]*1.01, '#obs : '+str(n_ob), horizontalalignment='center', fontdict={'size':14}, color='white')
add_n_obs(df,group_col='class',y='hwy')
# Decoration
plt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)
plt.ylim(10, 40)
plt.show()
图26
27 包点+箱形图 (Dot + Box Plot)包点+箱形图 (Dot + Box Plot)传达类似于分组的箱形图信息。 此外,这些点可以了解每组中有多少数据点。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Draw Plot
plt.figure(figsize=(13,10), dpi= 80)
sns.boxplot(x='class', y='hwy', data=df, hue='cyl')
sns.stripplot(x='class', y='hwy', data=df, color='black', size=3, jitter=1)
for i in range(len(df['class'].unique())-1):
plt.vlines(i+.5, 10, 45, linestyles='solid', colors='gray', alpha=0.2)
# Decoration
plt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)
plt.legend(title='Cylinders')
plt.show()
图27
28 小提琴图 (Violin Plot)小提琴图是箱形图在视觉上令人愉悦的替代品。 小提琴的形状或面积取决于它所持有的观察次数。 但是,小提琴图可能更难以阅读,并且在专业设置中不常用。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Draw Plot
plt.figure(figsize=(13,10), dpi= 80)
sns.violinplot(x='class', y='hwy', data=df, scale='width', inner='quartile')
# Decoration
plt.title('Violin Plot of Highway Mileage by Vehicle Class', fontsize=22)
plt.show()
图28
29 人口金字塔 (Population Pyramid)人口金字塔可用于显示由数量排序的组的分布。 或者它也可以用于显示人口的逐级过滤,因为它在下面用于显示有多少人通过营销渠道的每个阶段。
# Read data
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv')
# Draw Plot
plt.figure(figsize=(13,10), dpi= 80)
group_col = 'Gender'
order_of_bars = df.Stage.unique()[::-1]
colors = [plt.cm.Spectral(i/float(len(df[group_col].unique())-1)) for i in range(len(df[group_col].unique()))]
for c, group in zip(colors, df[group_col].unique()):
sns.barplot(x='Users', y='Stage', data=df.loc[df[group_col]==group, :], order=order_of_bars, color=c, label=group)
# Decorations
plt.xlabel('$Users$')
plt.ylabel('Stage of Purchase')
plt.yticks(fontsize=12)
plt.title('Population Pyramid of the Marketing Funnel', fontsize=22)
plt.legend()
plt.show()
图29
30 分类图 (Categorical Plots)由 seaborn库 提供的分类图可用于可视化彼此相关的2个或更多分类变量的计数分布。
# Load Dataset
titanic = sns.load_dataset('titanic')
# Plot
g = sns.catplot('alive', col='deck', col_wrap=4,
data=titanic[titanic.deck.notnull()],
kind='count', height=3.5, aspect=.8,
palette='tab20')
fig.suptitle('sf')
plt.show()
图30
# Load Dataset
titanic = sns.load_dataset('titanic')
# Plot
sns.catplot(x='age', y='embark_town',
hue='sex', col='class',
data=titanic[titanic.embark_town.notnull()],
orient='h', height=5, aspect=1, palette='tab10',
kind='violin', dodge=True, cut=0, bw=.2)
图30-2
五、组成 (Composition) 31 华夫饼图 (Waffle Chart)可以使用 pywaffle包 创建华夫饼图,并用于显示更大群体中的组的组成。
(『Python数据之道』注:需要安装 pywaffle 库)
#! pip install pywaffle
# Reference: https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechart
from pywaffle import Waffle
# Import
df_raw = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Prepare Data
df = df_raw.groupby('class').size().reset_index(name='counts')
n_categories = df.shape[0]
colors = [plt.cm.inferno_r(i/float(n_categories)) for i in range(n_categories)]
# Draw Plot and Decorate
fig = plt.figure(
FigureClass=Waffle,
plots={
'111': {
'values': df['counts'],
'labels': ['{0} ({1})'.format(n[0], n[1]) for n in df[['class', 'counts']].itertuples()],
'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12},
'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize':18}
},
},
rows=7,
colors=colors,
figsize=(16, 9)
)
图31
图31-2
32 饼图 (Pie Chart)饼图是显示组成的经典方式。 然而,现在通常不建议使用它,因为馅饼部分的面积有时会变得误导。 因此,如果您要使用饼图,强烈建议明确记下饼图每个部分的百分比或数字。
# Import
df_raw = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Prepare Data
df = df_raw.groupby('class').size()
# Make the plot with pandas
df.plot(kind='pie', subplots=True, figsize=(8, 8))
plt.title('Pie Chart of Vehicle Class - Bad')
plt.ylabel('')
plt.show()
图32
图32-2
33 树形图 (Treemap)树形图类似于饼图,它可以更好地完成工作而不会误导每个组的贡献。
(『Python数据之道』注:需要安装 squarify 库)
# pip install squarify
import squarify
# Import Data
df_raw = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Prepare Data
df = df_raw.groupby('class').size().reset_index(name='counts')
labels = df.apply(lambda x: str(x[0]) + '
(' + str(x[1]) + ')', axis=1)
sizes = df['counts'].values.tolist()
colors = [plt.cm.Spectral(i/float(len(labels))) for i in range(len(labels))]
# Draw Plot
plt.figure(figsize=(12,8), dpi= 80)
squarify.plot(sizes=sizes, label=labels, color=colors, alpha=.8)
# Decorate
plt.title('Treemap of Vechile Class')
plt.axis('off')
plt.show()
图33
34 条形图 (Bar Chart)条形图是基于计数或任何给定指标可视化项目的经典方式。 在下面的图表中,我为每个项目使用了不同的颜色,但您通常可能希望为所有项目选择一种颜色,除非您按组对其进行着色。 颜色名称存储在下面代码中的all_colors中。 您可以通过在plt.plot()中设置颜色参数来更改条的颜色。
import random
# Import Data
df_raw = pd.read_csv('https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv')
# Prepare Data
df = df_raw.groupby('manufacturer').size().reset_index(name='counts')
n = df['manufacturer'].unique().__len__()+1
all_colors = list(plt.cm.colors.cnames.keys())
random.seed(100)
c = random.choices(all_colors, k=n)
# Plot Bars
plt.figure(figsize=(16,10), dpi= 80)
plt.bar(df['manufacturer'], df['counts'], color=c, width=.5)
for i, val in enumerate(df['counts'].values):
plt.text(i, val, float(val), horizontalalignment='center', verticalalignment='bottom', fontdict={'fontweight':500, 'size':12})
# Decoration
plt.gca().set_xticklabels(df['manufacturer'], rotation=60, horizontalalignment= 'right')
plt.title('Number of Vehicles by Manaufacturers', fontsize=22)
plt.ylabel('# Vehicles')
plt.ylim(0, 45)
plt.show()
图34
六、变化 (Change) 35 时间序列图 (Time Series Plot)时间序列图用于显示给定度量随时间变化的方式。 在这里,您可以看到 1949年 至 1969年间航空客运量的变化情况。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')
# Draw Plot
plt.figure(figsize=(16,10), dpi= 80)
plt.plot('date', 'traffic', data=df, color='tab:red')
# Decoration
plt.ylim(50, 750)
xtick_location = df.index.tolist()[::12]
xtick_labels = [x[-4:] for x in df.date.tolist()[::12]]
plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=0, fontsize=12, horizontalalignment='center', alpha=.7)
plt.yticks(fontsize=12, alpha=.7)
plt.title('Air Passengers Traffic (1949 - 1969)', fontsize=22)
plt.grid(axis='both', alpha=.3)
# Remove borders
plt.gca().spines['top'].set_alpha(0.0)
plt.gca().spines['bottom'].set_alpha(0.3)
plt.gca().spines['right'].set_alpha(0.0)
plt.gca().spines['left'].set_alpha(0.3)
plt.show()
图35
36 带波峰波谷标记的时序图 (Time Series with Peaks and Troughs Annotated)下面的时间序列绘制了所有峰值和低谷,并注释了所选特殊事件的发生。
图36
37 自相关和部分自相关图 (Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot)自相关图(ACF图)显示时间序列与其自身滞后的相关性。 每条垂直线(在自相关图上)表示系列与滞后0之间的滞后之间的相关性。图中的蓝色阴影区域是显着性水平。 那些位于蓝线之上的滞后是显着的滞后。
那么如何解读呢?
对于空乘旅客,我们看到多达14个滞后跨越蓝线,因此非常重要。 这意味着,14年前的航空旅客交通量对今天的交通状况有影响。
PACF在另一方面显示了任何给定滞后(时间序列)与当前序列的自相关,但是删除了滞后的贡献。
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')
# Draw Plot
fig, (ax1, ax2) = plt.subplots(1, 2,figsize=(16,6), dpi= 80)
plot_acf(df.traffic.tolist(), ax=ax1, lags=50)
plot_pacf(df.traffic.tolist(), ax=ax2, lags=20)
# Decorate
# lighten the borders
ax1.spines['top'].set_alpha(.3); ax2.spines['top'].set_alpha(.3)
ax1.spines['bottom'].set_alpha(.3); ax2.spines['bottom'].set_alpha(.3)
ax1.spines['right'].set_alpha(.3); ax2.spines['right'].set_alpha(.3)
ax1.spines['left'].set_alpha(.3); ax2.spines['left'].set_alpha(.3)
# font size of tick labels
ax1.tick_params(axis='both', labelsize=12)
ax2.tick_params(axis='both', labelsize=12)
plt.show()
图37
38 交叉相关图 (Cross Correlation plot)交叉相关图显示了两个时间序列相互之间的滞后。
图38
39 时间序列分解图 (Time Series Decomposition Plot)时间序列分解图显示时间序列分解为趋势,季节和残差分量。
from statsmodels.tsa.seasonal import seasonal_decompose
from dateutil.parser import parse
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')
dates = pd.DatetimeIndex([parse(d).strftime('%Y-%m-01') for d in df['date']])
df.set_index(dates, inplace=True)
# Decompose
result = seasonal_decompose(df['traffic'], model='multiplicative')
# Plot
plt.rcParams.update({'figure.figsize': (10,10)})
result.plot().suptitle('Time Series Decomposition of Air Passengers')
plt.show()
图39
40 多个时间序列 (Multiple Time Series)您可以绘制多个时间序列,在同一图表上测量相同的值,如下所示。
图40
41 使用辅助 Y 轴来绘制不同范围的图形 (Plotting with different scales using secondary Y axis)如果要显示在同一时间点测量两个不同数量的两个时间序列,则可以在右侧的辅助Y轴上再绘制第二个系列。
图41
42 带有误差带的时间序列 (Time Series with Error Bands)如果您有一个时间序列数据集,每个时间点(日期/时间戳)有多个观测值,则可以构建带有误差带的时间序列。 您可以在下面看到一些基于每天不同时间订单的示例。 另一个关于45天持续到达的订单数量的例子。
在该方法中,订单数量的平均值由白线表示。 并且计算95%置信区间并围绕均值绘制。
图42
图42-2
43 堆积面积图 (Stacked Area Chart)堆积面积图可以直观地显示多个时间序列的贡献程度,因此很容易相互比较。
图43
44 未堆积的面积图 (Area Chart UnStacked)未堆积面积图用于可视化两个或更多个系列相对于彼此的进度(起伏)。 在下面的图表中,您可以清楚地看到随着失业中位数持续时间的增加,个人储蓄率会下降。 未堆积面积图表很好地展示了这种现象。
# Import Data
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/economics.csv')
# Prepare Data
x = df['date'].values.tolist()
y1 = df['psavert'].values.tolist()
y2 = df['uempmed'].values.tolist()
mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']
columns = ['psavert', 'uempmed']
# Draw Plot
fig, ax = plt.subplots(1, 1, figsize=(16,9), dpi= 80)
ax.fill_between(x, y1=y1, y2=0, label=columns[1], alpha=0.5, color=mycolors[1], linewidth=2)
ax.fill_between(x, y1=y2, y2=0, label=columns[0], alpha=0.5, color=mycolors[0], linewidth=2)
# Decorations
ax.set_title('Personal Savings Rate vs Median Duration of Unemployment', fontsize=18)
ax.set(ylim=[0, 30])
ax.legend(loc='best', fontsize=12)
plt.xticks(x[::50], fontsize=10, horizontalalignment='center')
plt.yticks(np.arange(2.5, 30.0, 2.5), fontsize=10)
plt.xlim(-10, x[-1])
# Draw Tick lines
for y in np.arange(2.5, 30.0, 2.5):
plt.hlines(y, xmin=0, xmax=len(x), colors='black', alpha=0.3, linestyles='--', lw=0.5)
# Lighten borders
plt.gca().spines['top'].set_alpha(0)
plt.gca().spines['bottom'].set_alpha(.3)
plt.gca().spines['right'].set_alpha(0)
plt.gca().spines['left'].set_alpha(.3)
plt.show()
图44
45 日历热力图 (Calendar Heat Map)与时间序列相比,日历地图是可视化基于时间的数据的备选和不太优选的选项。 虽然可以在视觉上吸引人,但数值并不十分明显。 然而,它可以很好地描绘极端值和假日效果。
(『Python数据之道』注:需要安装 calmap 库)
import matplotlib as mpl
# pip install calmap
# Python数据之道 备注
import calmap
# Import Data
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/yahoo.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
# Plot
plt.figure(figsize=(16,10), dpi= 80)
calmap.calendarplot(df['2014']['VIX.Close'], fig_kws={'figsize': (16,10)}, yearlabel_kws={'color':'black', 'fontsize':14}, subplot_kws={'title':'Yahoo Stock Prices'})
plt.show()
图45
46 季节图 (Seasonal Plot)季节图可用于比较上一季中同一天(年/月/周等)的时间序列。
图46
七、分组 (Groups) 47 树状图 (Dendrogram)树形图基于给定的距离度量将相似的点组合在一起,并基于点的相似性将它们组织在树状链接中。
import scipy.cluster.hierarchy as shc
# Import Data
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')
# Plot
plt.figure(figsize=(16, 10), dpi= 80)
plt.title('USArrests Dendograms', fontsize=22)
dend = shc.dendrogram(shc.linkage(df[['Murder', 'Assault', 'UrbanPop', 'Rape']], method='ward'), labels=df.State.values, color_threshold=100)
plt.xticks(fontsize=12)
plt.show()
图47
48 簇状图 (Cluster Plot)簇状图 (Cluster Plot)可用于划分属于同一群集的点。 下面是根据USArrests数据集将美国各州分为5组的代表性示例。 此图使用“谋杀”和“攻击”列作为X和Y轴。 或者,您可以将第一个到主要组件用作X轴和Y轴。
from sklearn.cluster import AgglomerativeClustering
from scipy.spatial import ConvexHull
# Import Data
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')
# Agglomerative Clustering
cluster = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
cluster.fit_predict(df[['Murder', 'Assault', 'UrbanPop', 'Rape']])
# Plot
plt.figure(figsize=(14, 10), dpi= 80)
plt.scatter(df.iloc[:,0], df.iloc[:,1], c=cluster.labels_, cmap='tab10')
# Encircle
def encircle(x,y, ax=None, **kw):
if not ax: ax=plt.gca()
p = np.c_[x,y]
hull = ConvexHull(p)
poly = plt.Polygon(p[hull.vertices,:], **kw)
ax.add_patch(poly)
# Draw polygon surrounding vertices
encircle(df.loc[cluster.labels_ == 0, 'Murder'], df.loc[cluster.labels_ == 0, 'Assault'], ec='k', fc='gold', alpha=0.2, linewidth=0)
encircle(df.loc[cluster.labels_ == 1, 'Murder'], df.loc[cluster.labels_ == 1, 'Assault'], ec='k', fc='tab:blue', alpha=0.2, linewidth=0)
encircle(df.loc[cluster.labels_ == 2, 'Murder'], df.loc[cluster.labels_ == 2, 'Assault'], ec='k', fc='tab:red', alpha=0.2, linewidth=0)
encircle(df.loc[cluster.labels_ == 3, 'Murder'], df.loc[cluster.labels_ == 3, 'Assault'], ec='k', fc='tab:green', alpha=0.2, linewidth=0)
encircle(df.loc[cluster.labels_ == 4, 'Murder'], df.loc[cluster.labels_ == 4, 'Assault'], ec='k', fc='tab:orange', alpha=0.2, linewidth=0)
# Decorations
plt.xlabel('Murder'); plt.xticks(fontsize=12)
plt.ylabel('Assault'); plt.yticks(fontsize=12)
plt.title('Agglomerative Clustering of USArrests (5 Groups)', fontsize=22)
plt.show()
图48
49 安德鲁斯曲线 (Andrews Curve)安德鲁斯曲线有助于可视化是否存在基于给定分组的数字特征的固有分组。 如果要素(数据集中的列)无法区分组(cyl),那么这些线将不会很好地隔离,如下所示。
from pandas.plotting import andrews_curves
# Import
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/mtcars.csv')
df.drop(['cars', 'carname'], axis=1, inplace=True)
# Plot
plt.figure(figsize=(12,9), dpi= 80)
andrews_curves(df, 'cyl', colormap='Set1')
# Lighten borders
plt.gca().spines['top'].set_alpha(0)
plt.gca().spines['bottom'].set_alpha(.3)
plt.gca().spines['right'].set_alpha(0)
plt.gca().spines['left'].set_alpha(.3)
plt.title('Andrews Curves of mtcars', fontsize=22)
plt.xlim(-3,3)
plt.grid(alpha=0.3)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
图49
50 平行坐标 (Parallel Coordinates)平行坐标有助于可视化特征是否有助于有效地隔离组。 如果实现隔离,则该特征可能在预测该组时非常有用。
from pandas.plotting import parallel_coordinates
# Import Data
df_final = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/diamonds_filter.csv')
# Plot
plt.figure(figsize=(12,9), dpi= 80)
parallel_coordinates(df_final, 'cut', colormap='Dark2')
# Lighten borders
plt.gca().spines['top'].set_alpha(0)
plt.gca().spines['bottom'].set_alpha(.3)
plt.gca().spines['right'].set_alpha(0)
plt.gca().spines['left'].set_alpha(.3)
plt.title('Parallel Coordinated of Diamonds', fontsize=22)
plt.grid(alpha=0.3)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
图50
有话要说...