【问题标题】:Calculate values in date column based on time column根据时间列计算日期列中的值
【发布时间】:2021-05-03 03:51:30
【问题描述】:

我有一个如下所示的数据框:

**date**              **time**            **price**
NaN                      1103                   5  
NaN                      0010                   10
NaN                      0100                   6
NaN                      0201                   8
NaN                      0015                   7
12.03.2020               0400                   4
NaN                      0500                   6
NaN                      0800                   3
NaN                      1000                   4
NaN                      1140                   5
12.03.2020               1200                   2
NaN                      0030                   1
NaN                      0112                   0

我想通过时间字段计算日期来填充日期列中的 NaN 值。我的想法是在日期列中找到第一个非空值。一旦有了,我想 bfill() 和 ffill() 以这样的方式在午夜前后的时间测量中更改日期。因此,在我们的示例中,在第一个非空单元格的 bfill() 之后,数据将如下所示:

     **date**              **time**            **price**
    10.03.2020               1103                   5  
    11.03.2020               0010                   10
    11.03.2020               0100                   6
    11.03.2020               0201                   8
    12.03.2020               0015                   7
    12.03.2020               0400                   4
    NaN                      0500                   6
    NaN                      0800                   3
    NaN                      1000                   4
    NaN                      1140                   5
    12.03.2020               1200                   2
    NaN                      0030                   1
    NaN                      0112                   0

这是 ffil() 从第一个非空日期值开始的样子:

          **date**             **time**            **price**
        10.03.2020               1103                   5  
        11.03.2020               0010                   10
        11.03.2020               0100                   6
        11.03.2020               0201                   8
        12.03.2020               0015                   7
        12.03.2020               0400                   4
        12.03.2020               0500                   6
        12.03.2020               0800                   3
        12.03.2020               1000                   4
        12.03.2020               1140                   5
        12.03.2020               1200                   2
        13.03.2020               0030                   1
        13.03.2020               0112                   0

值得注意的是,第一个非空值可以出现在日期列中的任何位置。将不胜感激解决这个问题的一些帮助。谢谢

date = [NaN,NaN,NaN,NaN,NaN,"12.03.2020", NaN,NaN,NaN,NaN, "12.03.2020", NaN, NaN}
time = [1103,0010,0100,0201,0015,0400,0500,0800,1000,1140,1200,0030,0112]
price= [5,10,6,8,7,4,6,3,4,5,2,1,0]

编辑:添加列表

【问题讨论】:

  • 您能否以列表格式发布您的数据以便于重新创建?另外,你确定 bfill 和 ffill 是一致的,两天之间没有冲突或歧义吗?
  • 我已经添加了列表,但是我不确定如何输入 NaN。是的 bfill() 和 ffill() 是一致的,只有在午夜之后才会改变日期。
  • 我们如何知道与 12.03.2020 相关的时间是上午还是下午?如果他们是上午,为什么我们必须在下一行移动到 13.03?这些似乎没有很好的定义
  • 时间采用 24 小时制。所以上午 12:00(午夜)到下午 12:00 是 24 小时格式的 0000 - 1200。

标签: python python-3.x pandas dataframe


【解决方案1】:

迭代Shubham's DateOffset idea,这是一个计算相对于某个已知日期的偏移量并将偏移量应用为Timedelta的版本:

df.date = pd.to_datetime(df.date, dayfirst=True)
df.time = pd.to_datetime(df.time, format='%H%M').dt.time
offset = df.time.shift().bfill().gt(df.time).cumsum()

known = df.date.notnull().idxmax()
offset -= offset.loc[known]

df.date = df.date.loc[known] + pd.to_timedelta(offset, unit='d')

详情

  1. 每当time 大于后续time 时计算偏移量:
df.date = pd.to_datetime(df.date, dayfirst=True)
df.time = pd.to_datetime(df.time, format='%H%M').dt.time
offset = df.time.shift().bfill().gt(df.time).cumsum()

# array([0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3])
  1. 找到一个known 日期用作偏移量的轴心点(这里我使用了第一个非空日期),其中known 日期的偏移量为0,而其他偏移量相对于known:
known = df.date.notnull().idxmax()
offset -= offset.loc[known]

# array([-2, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  1,  1])
  1. 转换偏移量to_timedelta() 并将它们添加到known 日期:
df.date = df.date.loc[known] + pd.to_timedelta(offset, unit='d')

#          date      time  value
# 0  2020-03-10  11:03:00      5
# 1  2020-03-11  00:10:00     10
# 2  2020-03-11  01:00:00      6
# 3  2020-03-11  02:01:00      8
# 4  2020-03-12  00:15:00      7
# 5  2020-03-12  04:00:00      4
# 6  2020-03-12  05:00:00      6
# 7  2020-03-12  08:00:00      3
# 8  2020-03-12  10:00:00      4
# 9  2020-03-12  11:40:00      5
# 10 2020-03-12  12:00:00      2
# 11 2020-03-13  00:30:00      1
# 12 2020-03-13  01:12:00      0

【讨论】:

  • 好答案!我们可以将offset.apply(lambda x: df.date.iloc[known] + pd.DateOffset(days=x)) 简化为df.date.loc[known] + pd.to_timedelta(offset, unit='d'),因为日期中没有时区信息,所以我猜timedelta 也可以正常工作:)
  • @ShubhamSharma 啊,有道理!谢谢——更新了
【解决方案2】:

试试这个。我不熟悉您的日期格式,并假设它们是文本格式

currDate=[]

def ffill(row,direction=1):
    global currDate
    if not currDate and pd.isna(row['date']): #could be check if date is blank string
        return None
    if not currDate:
        dt=[int(x) for x in reversed(row['date'].split('.'))]
        dt= datetime.datetime(*dt)
        currDate=[dt, row['time']]
        return dt
    if row['time']*direction>currDate[1]*direction:
        currDate[1]=row['time']
        return currDate[0]
    else:
        currDate=[currDate[0]+relativedelta(days=direction),row['time']]
        return currDate[0]
def bfill(row):
    return ffill(row,-1)
df['ffill']=df.apply(ffill,axis=1)
df.sort_index(0,None,False,True)
currDate=[]
df['bfill']=df.apply(bfill,axis=1)
df.sort_index(0,None,True,True)
df

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多