使用seaborn绘制时间序列数据

17

假设我使用以下方法创建一个完全随机的Dataframe

from pandas.util import testing
from random import randrange

def random_date(start, end):
    delta = end - start
    int_delta = (delta.days * 24 * 60 * 60) + delta.seconds
    random_second = randrange(int_delta)
    return start + timedelta(seconds=random_second)

def rand_dataframe():
  df = testing.makeDataFrame()
  df['date'] = [random_date(datetime.date(2014,3,18),datetime.date(2014,4,1)) for x in xrange(df.shape[0])]
  df.sort(columns=['date'], inplace=True)      
  return df

df = rand_dataframe()
这导致在本文底部显示的数据帧。我想使用seaborn软件包中的时间序列可视化功能绘制我的ABCD列,以便获得类似于以下内容的内容:

enter image description here

如何解决这个问题?根据我在此笔记本上读到的信息,调用应该是:
sns.tsplot(df, time="time", unit="unit", condition="condition", value="value")

但是这似乎需要使用不同的方式表示数据框,其中列以某种方式对时间、单位、条件和值进行编码,而这并不是我的情况。我该如何将我的数据框(如下所示)转换为此格式?

这是我的数据框:

      date         A         B         C         D

2014-03-18  1.223777  0.356887  1.201624  1.968612
2014-03-18  0.160730  1.888415  0.306334  0.203939
2014-03-18 -0.203101 -0.161298  2.426540  0.056791
2014-03-18 -1.350102  0.990093  0.495406  0.036215
2014-03-18 -1.862960  2.673009 -0.545336 -0.925385
2014-03-19  0.238281  0.468102 -0.150869  0.955069
2014-03-20  1.575317  0.811892  0.198165  1.117805
2014-03-20  0.822698 -0.398840 -1.277511  0.811691
2014-03-20  2.143201 -0.827853 -0.989221  1.088297
2014-03-20  0.299331  1.144311 -0.387854  0.209612
2014-03-20  1.284111 -0.470287 -0.172949 -0.792020
2014-03-22  1.031994  1.059394  0.037627  0.101246
2014-03-22  0.889149  0.724618  0.459405  1.023127
2014-03-23 -1.136320 -0.396265 -1.833737  1.478656
2014-03-23 -0.740400 -0.644395 -1.221330  0.321805
2014-03-23 -0.443021 -0.172013  0.020392 -2.368532
2014-03-23  1.063545  0.039607  1.673722  1.707222
2014-03-24  0.865192 -0.036810 -1.162648  0.947431
2014-03-24 -1.671451  0.979238 -0.701093 -1.204192
2014-03-26 -1.903534 -1.550349  0.267547 -0.585541
2014-03-27  2.515671 -0.271228 -1.993744 -0.671797
2014-03-27  1.728133 -0.423410 -0.620908  1.430503
2014-03-28 -1.446037 -0.229452 -0.996486  0.120554
2014-03-28 -0.664443 -0.665207  0.512771  0.066071
2014-03-29 -1.093379 -0.936449 -0.930999  0.389743
2014-03-29  1.205712 -0.356070 -0.595944  0.702238
2014-03-29 -1.069506  0.358093  1.217409 -2.286798
2014-03-29  2.441311  1.391739 -0.838139  0.226026
2014-03-31  1.471447 -0.987615  0.201999  1.228070
2014-03-31 -0.050524  0.539846  0.133359 -0.833252

最终,我要找的是一种图层叠加的方式(每列一个), 其中每个图形如下所示(请注意,不同CI值对应不同的α值):

                     图片描述


你的索引中有重复的日期。这是故意的吗?如果是,那有什么重要性? - Paul H
感谢@PaulH。虽然它们可以移动到一列中,但这是有意的。我每个日期有多个样本,并且我想在图中捕获每个日期的带厚度的变化。 - Amelio Vazquez-Reina
还有,你能添加你的导入语句吗?randrange 是从哪里来的? - Paul H
你想让误差带显示你所拥有的数据的Q1和Q3分位数吗?目前tsplot的工作方式是,误差带会在每个时间点显示中心趋势估计的置信区间,这与之略有不同。 - mwaskom
感谢@mwaskom - 完全没有问题。我肯定可以接受tsplot默认的方式。我可能稍后会找出正确的带厚度。 - Amelio Vazquez-Reina
显示剩余2条评论
1个回答

37

我认为tsplot在你拥有的数据上不会起作用。它对输入数据的假设是,在每个时间点上您已经对相同的单位进行了采样(尽管某些单位可能会缺失时间点)。

例如,假设您连续一个月每天从同一组人中测量血压,然后想要按条件(也许是他们的饮食)绘制平均血压的图表。tsplot可以通过以下方式调用来实现:sns.tsplot(df, time="day", unit="person", condition="diet", value="blood_pressure")

这种情况与每天随机从不同饮食组中抽取一些人并测量其血压的大型人群不同。从您给出的示例中,似乎您的数据结构就是这样的。

但是,使用 matplotlib 和 pandas 的混合方法实现您想要的效果并不难:

# Read in the data from the stackoverflow question
df = pd.read_clipboard().iloc[1:]

# Convert it to "long-form" or "tidy" representation
df = pd.melt(df, id_vars=["date"], var_name="condition")

# Plot the average value by condition and date
ax = df.groupby(["condition", "date"]).mean().unstack("condition").plot()

# Get a reference to the x-points corresponding to the dates and the the colors
x = np.arange(len(df.date.unique()))
palette = sns.color_palette()

# Calculate the 25th and 75th percentiles of the data
# and plot a translucent band between them
for cond, cond_df in df.groupby("condition"):
    low = cond_df.groupby("date").value.apply(np.percentile, 25)
    high = cond_df.groupby("date").value.apply(np.percentile, 75)
    ax.fill_between(x, low, high, alpha=.2, color=palette.pop(0))

这段代码会生成:

在此输入图片描述


谢谢。你为什么认为 tsplot 不起作用?我可以理解统计假设不适用,但是 tsplot 如何知道样本来自哪里?它是否假定每个日期具有恒定数量的元素? - Amelio Vazquez-Reina
1
这就是 unit 参数的作用 -- 你告诉它每个样本对应的单位,然后它期望每个时间点都会有相应的单位表示。 - mwaskom
我之所以问这个问题,是因为我特别关注tsplot能否针对置信区间的不同值使用不同的alpha值(我在更新了原帖,在结尾处强调了这一点)。 - Amelio Vazquez-Reina
3
你可以添加一个内循环,针对不同的区间重复执行 fill_between 代码块。tsplot 只是在彼此叠加的多个图形上绘制,与 Alpha 本身无关。 - mwaskom
1
有没有可能避免将数据转换为“长格式”(这不是高效的)? - tagoma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接