【问题标题】:How to insert values at certain time of a DatetimeIndex如何在 DatetimeIndex 的特定时间插入值
【发布时间】:2019-05-22 02:37:32
【问题描述】:

我在下面有一个可重现的代码:

import pandas as pd
import datetime

foo = pd.read_csv("http://m.uploadedit.com/bbtc/1545406250692.txt", header=None, names=["Stock","Date","Time", "Open", "High", "Low", "Close", "Volume", "OI"], dtype={"Stock":"category"}, parse_dates= [['Date', 'Time']], index_col="Date_Time")
foo.sort_index(inplace=True)
bar = foo.between_time('09:00:00', '15:30:00') #Dropping post and pre market data i.e. from index 15:31 - 16:35

#resampling the data by 120 Minutes (2 hours)
twohour = bar.loc["2018-11-22 09:08:00":].resample('120Min',closed = 'right',label = 'left', base=75).agg({'Open': 'first', 'High': 'max', 'Low': 'min','Close': 'last'}).dropna()
twohour.head(7)

Out[]:
                    Close   High    Open    Low
Date_Time               
2018-11-22 07:15:00 321.3   321.30  321.30  321.30
2018-11-22 09:15:00 324.5   326.90  320.10  320.00
2018-11-22 11:15:00 323.2   324.85  324.60  322.20
2018-11-22 13:15:00 319.9   324.35  323.20  319.50
2018-11-22 15:15:00 320.0   320.35  319.85  319.15
2018-11-26 07:15:00 324.90  324.90  324.90  324.90
2018-11-26 09:15:00 311.35  324.40  323.10  309.60

我希望时间为09:15:00 的索引中Open 列中的每个值都替换为时间为07:15:00 的索引中Close 列的值。

简而言之,我需要这个输出:

Out[]:
                    Close   High    Open    Low
Date_Time               
2018-11-22 07:15:00 321.3   321.30  321.30  321.30
2018-11-22 09:15:00 324.5   326.90  321.30  320.00
2018-11-22 11:15:00 323.2   324.85  324.60  322.20
2018-11-22 13:15:00 319.9   324.35  323.20  319.50
2018-11-22 15:15:00 320.0   320.35  319.85  319.15
2018-11-26 07:15:00 324.90  324.90  324.90  324.90
2018-11-26 09:15:00 311.35  324.40  324.90  309.60

我尝试通过将DateTimeindex 转换为字典然后替换值来使用.loc。但是字典没有排序,所以它需要对字典进行排序,代码变得越来越难看。 任何帮助将不胜感激。

【问题讨论】:

  • 在您的 DataFrame 中,有两行的“Date_Time”列值为“07:15:00”。替换时如何决定选择哪一个?
  • 在您有 9:15 的数据但没有 7:15 的记录的日期应该发生什么?
  • @L.B.如输出所示,我想用时间 9:15:00 替换索引上方的那个。
  • @ALollz 这不会发生,但如果发生了,我不想改变任何东西,我会保持数据不变。
  • @L.B.还没有,接下来 15 分钟试试。

标签: python pandas datetime dataframe


【解决方案1】:

您可以在比较之前将您的索引转换为timdelta字符串:

# timedelta option, vectorised & efficient
mask_bool = (df.index - df.index.normalize()) == '09:15:00'

# string alternative, inefficient
mask_bool = df.index.strftime('%H:%M') == '09:15'

然后通过locmask分配:

# Option 1: assign conditionally via loc
df.loc[mask_bool, 'Open'] = df['Close'].shift(1)

# Option 2: mask with pd.Series.mask
df['Open'] = df['Open'].mask(mask_bool, df['Close'].shift(1))

结果:

print(df)

                      Close    High    Open     Low
Date_Time                                          
2018-11-22 07:15:00  321.30  321.30  321.30  321.30
2018-11-22 09:15:00  324.50  326.90  321.30  320.00
2018-11-22 11:15:00  323.20  324.85  324.60  322.20
2018-11-22 13:15:00  319.90  324.35  323.20  319.50
2018-11-22 15:15:00  320.00  320.35  319.85  319.15
2018-11-26 07:15:00  324.90  324.90  324.90  324.90
2018-11-26 09:15:00  311.35  324.40  324.90  309.60

性能基准测试

对于较大的数据帧,timedelta 矢量化版本应该是高效的,但请注意这将取决于系统和设置:

# Python 3.6.5, Pandas 0.23, NumPy 1.14.3

import pandas as pd
from datetime import time

df = pd.DataFrame.from_dict({'Date_Time': ['2018-11-22 07:15:00', '2018-11-22 09:15:00',
                                           '2018-11-22 11:15:00', '2018-11-22 13:15:00',
                                           '2018-11-22 15:15:00', '2018-11-26 07:15:00',
                                           '2018-11-26 09:15:00'],
                             'Close': [321.3, 324.5, 323.2, 319.9, 320.0, 324.9, 311.35],
                             'High': [321.3, 326.9, 324.85, 324.35, 320.35, 324.9, 324.4],
                             'Open': [321.3, 321.3, 324.6, 323.2, 319.85, 324.9, 324.9],
                             'Low': [321.3, 320.0, 322.2, 319.5, 319.15, 324.9, 309.6]})

df['Date_Time'] = pd.to_datetime(df['Date_Time'])
df = df.set_index('Date_Time')

df = pd.concat([df]*10**4)

%timeit (df.index - df.index.normalize()) == '09:15:00'  # 8.67 ms
%timeit df.index.strftime('%H:%M') == '09:15'            # 651 ms
%timeit df.index.time == time(9, 15)                     # 28.3 ms

【讨论】:

  • 谢谢@jpp。根据您的说法,哪个答案/代码会更快?你的答案还是 Vaishali 的答案?
  • @ArJuN,查看更新,计时布尔掩码瓶颈,timedelta 选项对于较大的数据帧来说是 3 个中最好的。
  • 你能用这两行代码再一次吗?我仍然在使用 loc
  • @Vaishali,我也看到了,我添加了带有版本号的完整基准测试代码,并添加了免责声明。当然,基准测试取决于系统。
  • 这是因为您只是在比较创建掩码的代码。当您根据切片分配数据时,会发生大量操作。我用这两行代码检查了时间。无论如何,我只是好奇,所以想看看我是否遗漏了什么。
【解决方案2】:

您可以使用 loc 选择所需的行并将 Open 列设置为 close.shift

import datetime 

df.loc[df.index.time == datetime.time(9, 15), 'Open'] = df['Close'].shift(1)


                    Close   High    Open    Low
Date_Time               
2018-11-22 07:15:00 321.30  321.30  321.30  321.30
2018-11-22 09:15:00 324.50  326.90  321.30  320.00
2018-11-22 11:15:00 323.20  324.85  324.60  322.20
2018-11-22 13:15:00 319.90  324.35  323.20  319.50
2018-11-22 15:15:00 320.00  320.35  319.85  319.15
2018-11-26 07:15:00 324.90  324.90  324.90  324.90
2018-11-26 09:15:00 311.35  324.40  324.90  309.60

编辑:比较时间

import time
start = time.clock()
df.loc[df.index.time == datetime.time(9, 15), 'Open'] = df['Close'].shift(1)
print (time.clock() - start)

0.006845999999999464


start = time.clock()
mask_bool = (df.index - df.index.normalize()) == '09:15:00'
df['Open'] = df['Open'].mask(mask_bool, df['Close'].shift(1))
print (time.clock() - start)

0.009392999999999319

【讨论】:

  • datetime.time(9, 15) 似乎不起作用,是吗?错误:TypeError: descriptor 'time' requires a 'datetime.datetime' object but received a 'int'
  • @zyxue 需要import datetime 而不是from datetime import datetime
  • 需要导入日期时间
  • @Vaishali,抱歉忘记替换所有df。代码运行良好。再次感谢!
  • @ArJuN,我刚刚添加了时间比较
猜你喜欢
  • 2015-06-26
  • 2018-05-28
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
相关资源
最近更新 更多