【问题标题】:Comparing timestamps in dataframe columns with pandas将数据框列中的时间戳与熊猫进行比较
【发布时间】:2021-05-13 15:08:37
【问题描述】:

假设我有一个这样的数据框

df1:

         datetime1                datetime2             
0   2021-05-09 19:52:14      2021-05-09 20:52:14  
1   2021-05-09 19:52:14      2021-05-09 21:52:14 
2           NaN                      NaN
3  2021-05-09 16:30:14               NaN
4           NaN                      NaN
5  2021-05-09 12:30:14        2021-05-09 14:30:14

我想比较 datetime1 和 datetime2 中的时间戳,并用它们之间的差异创建一个新列。

在某些情况下,我在 datetime1 和 datetime2 中没有值,或者我在 datatime1 中有值但在 datatime2 中没有值,所以有一种可能的方法可以在“差异”中获取 NaN如果在 datetime1 和 2 中没有时间戳,并且仅在 datetime1 中有时间戳,则获取与 datetime.now() 相比的差异并将其放在另一列中。

理想的df输出:

         datetime1             datetime2          Difference in H:m:s    Compared with datetime.now()
0   2021-05-09 19:52:14     2021-05-09 20:52:14       01:00:00                 NaN
1   2021-05-09 19:52:14     2021-05-09 21:52:14       02:00:00                 NaN
2           NaN                    NaN                  NaN                    NaN
3   2021-05-09 16:30:14            NaN                  NaN                e.g(04:00:00)
4           NaN                    NaN                  NaN                    NaN
5  2021-05-09 12:30:14    2021-05-09 14:30:14         02:00:00                 NaN

我尝试了@AndrejKesely 的解决方案,但如果 datetime1 和 datetime2 中没有时间戳,则会失败:

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)


# if datetime1/datetime2 aren't already datetime, apply `.to_datetime()`:
df["datetime1"] = pd.to_datetime(df["datetime1"])
df["datetime2"] = pd.to_datetime(df["datetime2"])

df["Difference in H:m:s"] = df.apply(
    lambda x: strfdelta(
        x["datetime2"] - x["datetime1"],
        "{hours:02d}:{minutes:02d}:{seconds:02d}",
    ),
    axis=1,
)
print(df)

【问题讨论】:

  • 你能不能只做df.dropna(inplace=True) 去掉 NaN 值然后做这个方法?
  • 它正在删除具有 NaN 值的行,我不想删除它们。我希望它们出现在我在问题中提到的理想数据帧输出中。

标签: python python-3.x pandas dataframe compare


【解决方案1】:

通过使用布尔索引(掩码)只选择符合条件的行来执行您需要的操作,并让 Pandas 用 NaN 填充缺失值:

def strfdelta(td: pd.Timestamp):
    seconds = td.total_seconds()
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    seconds = int(seconds % 60)
    return f"{hours:02}:{minutes:02}:{seconds:02}"

bm1 = df["datetime1"].notna() & df["datetime2"].notna()
bm2 = df["datetime1"].notna() & df["datetime2"].isna()

df["Difference in H:m:s"] = (df.loc[bm1, "datetime2"] - df.loc[bm1, "datetime1"]).apply(strfdelta)

df["Compared with datetime.now()"] = (datetime.now() - df.loc[bm2, "datetime1"]).apply(strfdelta)
>>> df

            datetime1           datetime2   Diff...    Comp...
0 2021-05-09 19:52:14 2021-05-09 20:52:14  01:00:00        NaN
1 2021-05-09 19:52:14 2021-05-09 21:52:14  02:00:00        NaN
2                 NaT                 NaT       NaN        NaN
3 2021-05-09 16:30:14                 NaT       NaN  103:09:19
4                 NaT                 NaT       NaN        NaN
5 2021-05-09 12:30:14 2021-05-09 14:30:14  02:00:00        NaN

【讨论】:

  • 谢谢@Corralien
  • 有没有办法可以只打印几小时而不是几天的差异?例如,如果差异是 30:00:00 要打印为 30:00:00 而不是 1 天 06:00:00?
  • 用你的strfdelta函数做你想做的事。如果你只喜欢固定格式 H:m:s,你的函数可以更简单。
  • 如何更改 strfdelta 函数以仅在数小时内而不是在天数内打印“差异”列?
  • @user14073111,我更新了strfdelta函数。
【解决方案2】:

您可以首先将datetime2 列中的所有NaN 值替换为datetime.now 值。因此,如果 datetime1NaN,则比较 datetime1 和现在会更容易。

你可以这样做:

df["datetime2"] = df["datetime2"].fillna(value=pandas.to_datetime('today').normalize(),axis=1)

那么你只剩下两个条件了:

  • 如果datetime1 列为空,则结果为NaN
  • 否则,结果是datetime1datetime2 列之间的差异(因为datetime2 列中没有剩余NaN)。

您可以使用:

import numpy as np

df["Difference in H:m:s"] = np.where(
    df["datetime1"].isnull(),
    pd.NA,
    df["datetime2"] - df["datetime1"]
)

您终于可以使用您提供的功能将Difference in H:m:s 格式化为所需的格式:

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)


df["Difference in H:m:s"] = df.apply(
    lambda x: strfdelta(
        x["Difference in H:m:s"],
        "{hours:02d}:{minutes:02d}:{seconds:02d}",
    ),
    axis=1,
)

完整的代码是:

import numpy as np

# if datetime1/datetime2 aren't already datetime, apply `.to_datetime()`:
df["datetime1"] = pd.to_datetime(df["datetime1"])
df["datetime2"] = pd.to_datetime(df["datetime2"])

df["datetime2"] = df["datetime2"].fillna(value=pandas.to_datetime('today').normalize(),axis=1)

df["Difference in H:m:s"] = np.where(
    df["datetime1"].isnull(),
    pd.NA,
    df["datetime2"] - df["datetime1"]
)

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)


df["Difference in H:m:s"] = df.apply(
    lambda x: strfdelta(
        x["Difference in H:m:s"],
        "{hours:02d}:{minutes:02d}:{seconds:02d}",
    ),
    axis=1,
)

【讨论】:

  • 谢谢@AlexTorx
猜你喜欢
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 2017-01-31
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 2021-10-27
  • 2021-09-14
相关资源
最近更新 更多