Python:在单行的两个不同列中绘制逗号分隔值(Pandas)

pst*_*mps 1 python list matplotlib pandas seaborn

假设我有一个结构如下的数据框:

Name        x        y
Joe       0,1,5    0,3,8
Sue       0,2,8    1,9,5
...
Harold    0,5,6    0,7,2
Run Code Online (Sandbox Code Playgroud)

我想将 x 轴和 y 轴中的值绘制在基于行的折线图上。实际上,有许多 x 和 y 值,但这些列中的每个 y 值始终对应一个 x 值。绘图的名称将是“名称”中的值。

我尝试通过首先将 x 和 y 转换为各自单独列中的列表来实现此目的,如下所示:

df['xval'] = df.['x'].str.split(',')
df['yval'] = df.['y'].str.split(',')
Run Code Online (Sandbox Code Playgroud)

然后将它们传递给seaborn:

ax = sns.lineplot(x=df['xval'], y=df['yval'], data=df)
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为 1)我收到一个错误,我认为这是由于尝试从数据帧传递列表所致,声称:

TypeError: unhashable type: 'list'
Run Code Online (Sandbox Code Playgroud)

2)我无法为特定线图指定 df['name'] 的值。解决这个问题的最佳方法是什么?

Hen*_*ker 5

数据和导入:

import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt

df = pd.DataFrame({
    'name': ['joe', 'sue', 'mike'],
    'x': ['0,1,5', '0,2,8', '0,4'],
    'y': ['0,3,8', '1,9,5', '1,6']
})
Run Code Online (Sandbox Code Playgroud)

我们应该转换df成可用的绘图格式。这使得所有的绘图变得更加容易。我们可以利用这一事实xy建立一对一的关系。请注意,我添加了第三个名称,其 xy 值为 2(而不是 3),以表明只要每行具有相同数量的 x 和 y 值,此方法就适用于每个名称的不同数量的 x 和 y。


创建plot_df

# Grab Name Column to Start Plot DF with
plot_df = df.loc[:, ['name']]
# Split X column
plot_df['x'] = df['x'].str.split(',')
# Explode X into Rows
plot_df = plot_df.explode('x').reset_index(drop=True)
# Split and Series Explode y in one step
# This works IF AND ONLY IF a 1-to-1 relationship for x and y
plot_df['y'] = df['y'].str.split(',').explode().reset_index(drop=True)
# These need to be numeric to plot correctly
plot_df.loc[:, ['x', 'y']] = plot_df.loc[:, ['x', 'y']].astype(int)
Run Code Online (Sandbox Code Playgroud)

plot_df

   name  x  y
0   joe  0  0
1   joe  1  3
2   joe  5  8
3   sue  0  1
4   sue  2  9
5   sue  8  5
6  mike  0  1
7  mike  4  6
Run Code Online (Sandbox Code Playgroud)

创建时使用的方法参考plot_df

  1. DataFrame.loc对数据框进行子集化
  2. Series.str.split将逗号分隔的值拆分为列表
  3. DataFrame.explode基于中的可迭代来升级 DataFramex
  4. DataFrame.reset_index使索引在爆炸后再次唯一
  5. Series.explode升级系列中的列表y
  6. Series.reset_index使索引在爆炸后再次唯一
  7. DataFrame.astype因为这些值最初是字符串,仅分裂和爆炸是不够的。需要转换为数字类型才能正确绘制

绘图(选项 1)

# Plot with hue set to name.
sns.lineplot(data=plot_df, x='x', y='y', hue='name')
plt.show()
Run Code Online (Sandbox Code Playgroud)

情节 1

绘制单独线条的参考:

  1. sns.lineplot来策划。请注意hue基于 来创建单独行的参数name
  2. pyplot.show显示。

绘制(选项 2.a)子图:

sns.relplot(data=plot_df, x='x', y='y', col='name', kind='line')
plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

图 2.a relplot (FacetGrid)

绘图(选项 2.b)子图:

# Use Grouper From plot_df
grouper = plot_df.groupby('name')

# Create Subplots based on the number of groups (ngroups)
fig, axes = plt.subplots(nrows=grouper.ngroups)

# Iterate over axes and groups
for ax, (grp_name, grp) in zip(axes, grouper):
    # Plot from each grp DataFrame on ax from axes
    sns.lineplot(data=grp, x='x', y='y', ax=ax, label=grp_name)

plt.show()
Run Code Online (Sandbox Code Playgroud)

图 2.b 子图 (matplotlib)

绘制子图的参考:

2.a

  1. relplotrow参数col可用于以与创建多条线类似的方式创建子图hue。这将返回一个seaborn.FacetGrid所以后处理将不同于lineplot返回matplotlib.axes.Axes

2.b

  1. groupby创建可用于绘制子图的迭代。
  2. pyplot.subplots创建要绘制的子图。
  3. groupby.ngroup计算组数。
  4. zip同时迭代轴和组。
  5. sns.lineplot来策划。需要注意label的是有图例。grp_name包含当前 DataFrame 中通用的当前键grp
  6. pyplot.show显示。

绘图选项 3(单独绘图):

# Plot from each grp DataFrame in it's own plot
for grp_name, grp in plot_df.groupby('name'):
    fig, ax = plt.subplots()
    sns.lineplot(data=grp, x='x', y='y', ax=ax)
    ax.set_title(grp_name)
    fig.show()
Run Code Online (Sandbox Code Playgroud)
乔情节 麦克情节 苏阴谋
乔情节 麦克情节 苏阴谋

绘制单独图的参考:

  1. groupby创建可用于单独绘制每个名称的迭代。
  2. pyplot.subplots创建单独的绘图来绘制。
  3. sns.lineplot来策划。需要注意label的是有图例。grp_name包含当前 DataFrame 中通用的当前键grp
  4. pyplot.show显示。

  • 非常好,但我建议使用“relplot(..., col='name')”作为子图,因为您已经有了长格式数据。 (2认同)