示例设置:
import pandas as pd
df = pd.DataFrame(
data={'ts':
[
'2008-11-05 07:45:23.100',
'2008-11-17 06:53:25.150',
'2008-12-02 07:36:18.643',
'2008-12-15 07:36:24.837',
'2009-01-06 07:03:47.387',
],
'val': range(5)})
df.ts = pd.to_datetime(df.ts)
df.set_index('ts', drop=False, inplace=True)
df
| ts | val
2008-11-05 07:45:23.100 | 2008-11-05 07:45:23.100 | 0
2008-11-17 06:53:25.150 | 2008-11-17 06:53:25.150 | 1
2008-12-02 07:36:18.643 | 2008-12-02 07:36:18.643 | 2
2008-12-15 07:36:24.837 | 2008-12-15 07:36:24.837 | 3
2009-01-06 07:03:47.387 | 2009-01-06 07:03:47.387 | 4
尽管索引是pd.Timestamp类型,但我可以使用时间戳的字符串表示形式对其进行过滤。例如:
df.loc['2008-11-05']
| ts | val
2008-11-05 07:45:23.100 | 2008-11-05 07:45:23.100 | 0
此外,熊猫具有非常方便的功能,当我的过滤器模糊时,它会返回理想的结果。例如:
df.loc['2008-12']
| ts | val
2008-12-02 07:36:18.643 | 2008-12-02 07:36:18.643 | 2
2008-12-15 07:36:24.837 | 2008-12-15 07:36:24.837 | 3
我的第一个问题是,如何使用字符串时间戳列表过滤df?例如,如果我运行下面的代码
df.loc[['2008-11-05','2008-12']]
,我想要得到的结果是
| ts | val
2008-11-05 07:45:23.100 | 2008-11-05 07:45:23.100 | 0
2008-12-02 07:36:18.643 | 2008-12-02 07:36:18.643 | 2
2008-12-15 07:36:24.837 | 2008-12-15 07:36:24.837 | 3
,但实际上我得到以下错误:
KeyError: "None of [Index(['2008-11-05', '2008-12'], dtype='object', name='ts')] are in the [index]"
我的第二个问题是,我可以对常规列执行类似的过滤逻辑吗?也就是说,如果我没有将ts
设置为索引,而是直接使用字符串过滤器过滤ts
列。
--------------------跟进2019-9-10 10:00 ----------------- ---
非常感谢以下所有答案。我不知道pd.Series.str.startswith
是否可以支持多个字符串的tuple
输入,或者pd.Series.str.contains
是否可以支持'|'
的使用。学习了新技能!
我认为所有基于astype(str)
的使用方法对我来说都有一个主要缺点:在美国,人们使用各种日期时间格式。除了“ 2008-11-05”,我公司常用的还有“ 2008-11-5”,“ 11/05/2008”,“ 11/5/2008”,“ 20081105”,“ 05nov2008”如果我使用基于字符串的方法,所有操作都会失败。
目前,我仍然必须遵循以下方法,该方法要求将列作为索引,并且似乎效率不高(我没有进行分析),但是应该足够健壮。我不明白为什么熊猫本身不支持它。
L = ['5nov2008','2008/12']
pd.concat([df.loc[val] for val in L]).drop_duplicates()
| ts | val
2008-11-05 07:45:23.100 | 2008-11-05 07:45:23.100 | 0
2008-12-02 07:36:18.643 | 2008-12-02 07:36:18.643 | 2
2008-12-15 07:36:24.837 | 2008-12-15 07:36:24.837 | 3
答案 0 :(得分:1)
您可以使用.contains()
,方法是先将其转换为str
res = df.loc[(df.index.astype(str).str.contains("2008-12"))
| (df.index.astype(str).str.contains('2008-11-05'))]
print(res)
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
yes you can apply filter on normal column like
df.loc[(df.ts.astype(str).str.contains("2008-12"))
|(df.ts.astype(str).str.contains('2008-11-05'))]
答案 1 :(得分:1)
这应该为您服务。
>>> df
ts val
0 2008-11-05 07:45:23.100 0
1 2008-11-17 06:53:25.150 1
2 2008-12-02 07:36:18.643 2
3 2008-12-15 07:36:24.837 3
4 2009-01-06 07:03:47.387 4
结果:
>>> df[df.apply(lambda row: row.astype(str).str.contains('2008-11-05')).any(axis=1)]
ts val
0 2008-11-05 07:45:23.100 0
OR ..
>>> df
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-11-17 06:53:25.150 2008-11-17 06:53:25.150 1
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
2009-01-06 07:03:47.387 2009-01-06 07:03:47.387 4
>>> df[df.apply(lambda row: row.astype(str).str.contains('2008-11-05')).any(axis=1)]
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
>>> df[df.apply(lambda row: row.astype(str).str.contains('2008-11-05|2008-12')).any(axis=1)]
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
答案 2 :(得分:1)
对于第一个问题,您可以使用pd.DataFrame.append
:
df.loc['2008-11-05'].append(df.loc['2008-12'])
# ts val
# ts
# 2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
# 2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
# 2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
对于第二个问题,您可以使用pd.Series.str.match
:
df.ts.astype(str).str.match('2008-11-05|2008-12')
# ts
# 2008-11-05 07:45:23.100 True
# 2008-11-17 06:53:25.150 False
# 2008-12-02 07:36:18.643 True
# 2008-12-15 07:36:24.837 True
# 2009-01-06 07:03:47.387 False
# Name: ts, dtype: bool
因此使用此作为布尔索引:
df[df.ts.astype(str).str.match('2008-11-05|2008-12')]
# ts val
# ts
# 2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
# 2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
# 2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
请注意,如果您的ts列已经是字符串类型,则可以省略astype(str)
部分。
答案 3 :(得分:1)
第一个想法只是通过concat
来加入在一起:
df1 = pd.concat([df.loc['2008-11-05'], df.loc['2008-12']], sort=True)
print (df1)
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
或针对正则表达式|
用boolean indexing
过滤,并用Series.str.contains
过滤,并用OR
过滤:
df1 = df[df.index.astype(str).str.contains('2008-11-05|2008-12')]
或使用Series.str.startswith
和元组:
df1 = df[df.index.astype(str).str.startswith(('2008-11-05', '2008-12'))]
print (df1)
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3
如果输入是字符串列表:
L = ['2008-11-05','2008-12']
df2 = df[df.ts.astype(str).str.contains('|'.join(L))]
类似:
df2 = df[df.ts.astype(str).str.startswith(tuple(L))]
print (df2)
ts val
0 2008-11-05 07:45:23.100 0
2 2008-12-02 07:36:18.643 2
3 2008-12-15 07:36:24.837 3
对于列,仅将index
更改为ts
:
df2 = df[df.ts.astype(str).str.contains('2008-11-05|2008-12')]
或者:
df2 = df[df.ts.astype(str).str.startswith(('2008-11-05', '2008-12'))]
print (df2)
ts val
0 2008-11-05 07:45:23.100 0
2 2008-12-02 07:36:18.643 2
3 2008-12-15 07:36:24.837 3
答案 4 :(得分:0)
您似乎偶然发现了一个错误!
这有效
df.loc['2008-11-05']
这有效
df.loc['2008-11-05':'2008-12-15']
但这不是您所提到的。
df.loc[['2008-11-05','2008-12-15']]
但是,您可以使用以下方法获取所需的行。
df.iloc[[0,2,3]]
ts val
ts
2008-11-05 07:45:23.100 2008-11-05 07:45:23.100 0
2008-12-02 07:36:18.643 2008-12-02 07:36:18.643 2
2008-12-15 07:36:24.837 2008-12-15 07:36:24.837 3