Skip to main content
 首页 » 编程设计

python之具有较低平滑度的散点图矩阵

2025年05月04日15落叶

对于像下面这样的具有低平滑度的散点图矩阵,Python 代码是什么?

我不确定图表的原始来源。我在this post上看到了在交叉验证上。省略号根据原始帖子定义协方差。我不确定这些数字是什么意思。

请您参考如下方法:

我修改了 pandas scatter_matrix 函数并得到了不错的结果:

import pandas as pd 
import numpy as np 
frame = pd.DataFrame(np.random.randn(100, 4), columns=['A','B','C','D']) 
fig = scatter_matrix_lowess(frame, alpha=0.4, figsize=(12,12)); 
fig.suptitle('Scatterplot matrix with lowess smoother', fontsize=16); 


这是 scatter_matrix_lowess 的代码:

def scatter_matrix_lowess(frame, alpha=0.5, figsize=None, grid=False, 
                   diagonal='hist', marker='.', density_kwds=None, 
                   hist_kwds=None, range_padding=0.05, **kwds): 
    """ 
    Draw a matrix of scatter plots with lowess smoother. 
    This is an adapted version of the pandas scatter_matrix function. 
 
    Parameters 
    ---------- 
    frame : DataFrame 
    alpha : float, optional 
        amount of transparency applied 
    figsize : (float,float), optional 
        a tuple (width, height) in inches 
    ax : Matplotlib axis object, optional 
    grid : bool, optional 
        setting this to True will show the grid 
    diagonal : {'hist', 'kde'} 
        pick between 'kde' and 'hist' for 
        either Kernel Density Estimation or Histogram 
        plot in the diagonal 
    marker : str, optional 
        Matplotlib marker type, default '.'     
    hist_kwds : other plotting keyword arguments 
        To be passed to hist function 
    density_kwds : other plotting keyword arguments 
        To be passed to kernel density estimate plot 
    range_padding : float, optional 
        relative extension of axis range in x and y 
        with respect to (x_max - x_min) or (y_max - y_min), 
        default 0.05 
    kwds : other plotting keyword arguments 
        To be passed to scatter function 
 
    Examples 
    -------- 
    >>> df = DataFrame(np.random.randn(1000, 4), columns=['A','B','C','D']) 
    >>> scatter_matrix_lowess(df, alpha=0.2) 
    """ 
 
    import matplotlib.pyplot as plt 
    from matplotlib.artist import setp 
    import pandas.core.common as com 
    from pandas.compat import range, lrange, lmap, map, zip 
    from statsmodels.nonparametric.smoothers_lowess import lowess 
 
    df = frame._get_numeric_data() 
    n = df.columns.size 
    fig, axes = plt.subplots(nrows=n, ncols=n, figsize=figsize, squeeze=False) 
 
    # no gaps between subplots 
    fig.subplots_adjust(wspace=0, hspace=0) 
 
    mask = com.notnull(df) 
 
    marker = _get_marker_compat(marker) 
 
    hist_kwds = hist_kwds or {} 
    density_kwds = density_kwds or {} 
 
    # workaround because `c='b'` is hardcoded in matplotlibs scatter method 
    kwds.setdefault('c', plt.rcParams['patch.facecolor']) 
 
    boundaries_list = [] 
    for a in df.columns: 
        values = df[a].values[mask[a].values] 
        rmin_, rmax_ = np.min(values), np.max(values) 
        rdelta_ext = (rmax_ - rmin_) * range_padding / 2. 
        boundaries_list.append((rmin_ - rdelta_ext, rmax_+ rdelta_ext)) 
 
    for i, a in zip(lrange(n), df.columns): 
        for j, b in zip(lrange(n), df.columns): 
            ax = axes[i, j] 
 
            if i == j: 
                values = df[a].values[mask[a].values] 
 
                # Deal with the diagonal by drawing a histogram there. 
                if diagonal == 'hist': 
                    ax.hist(values, **hist_kwds) 
 
                elif diagonal in ('kde', 'density'): 
                    from scipy.stats import gaussian_kde 
                    y = values 
                    gkde = gaussian_kde(y) 
                    ind = np.linspace(y.min(), y.max(), 1000) 
                    ax.plot(ind, gkde.evaluate(ind), **density_kwds) 
 
                ax.set_xlim(boundaries_list[i]) 
 
            else: 
                common = (mask[a] & mask[b]).values 
 
                ax.scatter(df[b][common], df[a][common], 
                           marker=marker, alpha=alpha, **kwds) 
                # The following 2 lines are new and add the lowess smoothing 
                ys = lowess(df[a][common], df[b][common]) 
                ax.plot(ys[:,0], ys[:,1], 'red', linewidth=1) 
 
                ax.set_xlim(boundaries_list[j]) 
                ax.set_ylim(boundaries_list[i]) 
 
            ax.set_xlabel('') 
            ax.set_ylabel('') 
 
            _label_axis(ax, kind='x', label=b, position='bottom', rotate=True) 
 
            _label_axis(ax, kind='y', label=a, position='left') 
 
            if j!= 0: 
                ax.yaxis.set_visible(False) 
            if i != n-1: 
                ax.xaxis.set_visible(False) 
 
    for ax in axes.flat: 
        setp(ax.get_xticklabels(), fontsize=8) 
        setp(ax.get_yticklabels(), fontsize=8) 
    return fig 
 
def _label_axis(ax, kind='x', label='', position='top', 
    ticks=True, rotate=False): 
 
    from matplotlib.artist import setp 
    if kind == 'x': 
        ax.set_xlabel(label, visible=True) 
        ax.xaxis.set_visible(True) 
        ax.xaxis.set_ticks_position(position) 
        ax.xaxis.set_label_position(position) 
        if rotate: 
            setp(ax.get_xticklabels(), rotation=90) 
    elif kind == 'y': 
        ax.yaxis.set_visible(True) 
        ax.set_ylabel(label, visible=True) 
        # ax.set_ylabel(a) 
        ax.yaxis.set_ticks_position(position) 
        ax.yaxis.set_label_position(position) 
    return 
 
def _get_marker_compat(marker): 
    import matplotlib.lines as mlines 
    import matplotlib as mpl 
    if mpl.__version__ < '1.1.0' and marker == '.': 
        return 'o' 
    if marker not in mlines.lineMarkers: 
        return 'o' 
    return marker