使用 loc 切片数据帧时,
df.loc[开始:结束]
包括开始和结束。使用 loc 时有没有简单的方法可以排除结束?
我能想到的最简单的是df.loc[start:end].iloc[:-1]
。
砍掉最后一个。
loc
包括开始和结束,一个不太理想的解决方法是获取索引位置并使用iloc
对数据框进行切片(假设您没有重复的索引(:
df=pd.DataFrame({'A':[1,2,3,4]}, index = ['a','b','c','d'])
df.iloc[df.index.get_loc('a'):df.index.get_loc('c')]
# A
#a 1
#b 2
df.loc['a':'c']
# A
#a 1
#b 2
#c 3
没有一个答案解决了end
不属于索引的情况。 更通用的解决方案是简单地将索引与start
和end
进行比较,这样您就可以强制它们中的任何一个包含独占。
df[(df.index >= start) & (df.index < end)]
例如:
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame(
{
"x": np.arange(48),
"y": np.arange(48) * 2,
},
index=pd.date_range("2020-01-01 00:00:00", freq="1H", periods=48)
)
>>> start = "2020-01-01 14:00"
>>> end = "2020-01-01 19:30" # this is not in the index
>>> df[(df.index >= start) & (df.index < end)]
x y
2020-01-01 14:00:00 14 28
2020-01-01 15:00:00 15 30
2020-01-01 16:00:00 16 32
2020-01-01 17:00:00 17 34
2020-01-01 18:00:00 18 36
2020-01-01 19:00:00 19 38
要切片DatetimeIndex
,您可以尝试此操作。它将在您的结束时间前一纳秒内抓取所有内容。这将排除结束时间(假设您没有使用 ns 精度(,但不一定是最后一次。
df.loc[start:(end - pd.Timedelta('1ns'))]
pd.RangeIndex
可用于切片带有.loc
的索引,并带有一个排除停止,前提是索引具有整数 dtype。这是一个简单的帮助程序:
class _eidx:
def __getitem__(self, s: slice) -> pd.RangeIndex:
return pd.RangeIndex(s.start, s.stop, s.step)
eidx = _eidx()
例:
df = pd.DataFrame({"x": range(10), "y": range(10, 20)})
print(df.loc[eidx[3:5]])
x y
3 3 13
4 4 14
一个更简单的方法是使用 pythonrange
:
print(df.loc[range(3, 5)])
x y
3 3 13
4 4 14
似乎没有任何真正巧妙的方法可以做到这一点,但我更喜欢富有表现力的解决方案(清楚我想做什么吗?
出于这个原因,我喜欢这个解决方案,即使它有点基本且有点笨拙。
这个想法的一个更强大、更有表现力和性能的版本是首先创建包含切片,然后过滤结果以排除端点:
df.loc[start:end][lambda _: _.index != end]
这个解决方案相当快(我已经设置了s = start; e = end
(,并使用一个名为ts
的系列来完成:
In [1]: %timeit ts[s:e]
135 µs ± 1.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [2]: %timeit ts[(ts.index >= s) & (ts.index < e)]
45.1 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [3]: %timeit ts[s:e][lambda s: s.index != e]
299 µs ± 1.75 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
通过允许中间变量,可以使其更具可读性:
inclusive = df.loc[start:end]
exclusive = inclusive[inclusive.index != end]
如果您使用的是另一个数据帧索引中的数据时间值。 假设您要使用的日期时间值是 df1.index[0],您可以使用 df1.index[0].Resolution 获取该索引的分辨率。
end = df1.index[0]
df.loc[:(end-end.resolution)]