Pandas:将时间序列转换为值变化跟踪

4 投票
1 回答
1513 浏览
提问于 2025-04-18 10:23

我一直在为这个问题苦恼,而且很不寻常的是,网上的信息也没能帮上忙。我在使用Pandas这个工具,但我觉得这应该是很多人都遇到的一个普遍问题,尤其是那些想要高效存储时间序列数据的人。

我有很多标准的每日时间序列数据,这些数据的值变化得很少,比如下面这样:

日期 值 01/02/2014 .1 01/03/2014 .1 01/04/2014 .5 01/05/2014 .5 01/06/2014 .5 01/07/2014 .1

我想把数据转换成只记录值发生变化的日期,所以上面的例子应该变成这样:

日期 值 01/02/2014 .1 01/04/2014 .5 01/07/2014 .1

不幸的是,像使用 drop_duplicates() 这样的函数会删除一些必要的值,尤其是在值回到之前的值时(就像我上面例子中的 .1)。

1 个回答

5

使用 shiftall 的组合:

In [98]:

import io
temp = """Date,Value
01/02/2014,.1
01/03/2014,.1
01/04/2014,.5
01/05/2014,.5
01/06/2014,.5
01/07/2014,.1"""
df = pd.read_csv(io.StringIO(temp))
df
Out[98]:
         Date  Value
0  01/02/2014    0.1
1  01/03/2014    0.1
2  01/04/2014    0.5
3  01/05/2014    0.5
4  01/06/2014    0.5
5  01/07/2014    0.1

In [99]:

df.loc[(df.shift() != df).all(axis=1)]
Out[99]:
         Date  Value
0  01/02/2014    0.1
2  01/04/2014    0.5
5  01/07/2014    0.1

这里我们把向下移动了一行的数据框(dataframe)和原始的数据框进行比较,然后我们想要比较每一列,并使用 all,同时传入 axis=1 来实现这个目的。

进一步分析一下,如果我们查看 df.shift() != df 的结果:

In [100]:

df.shift() != df
Out[100]:
   Date  Value
0  True   True
1  True  False
2  True   True
3  True  False
4  True  False
5  True   True

我们会得到一个包含布尔值(真或假)的数据框,但我们不能直接把这个作为掩码(mask)使用,我们想要检查所有行是否都是 True,所以我们使用 all

In [101]:

(df.shift() != df).all()
Out[101]:
Date      True
Value    False
dtype: bool

不过,默认情况下,它会检查所有列是否都是 True,而我们想要检查的是行的值,所以我们传入 axis=1

In [102]:

(df.shift() != df).all(axis=1)
Out[102]:
0     True
1    False
2     True
3    False
4    False
5     True
dtype: bool

现在我们可以把这个作为我们的布尔掩码,来实现我们想要的效果:

In [103]:

df.loc[(df.shift() != df).all(axis=1)]
Out[103]:
         Date  Value
0  01/02/2014    0.1
2  01/04/2014    0.5
5  01/07/2014    0.1

撰写回答