【问题标题】:Datetime column coerced to int when setting with .loc and slice使用 .loc 和 slice 设置时,日期时间列强制为 int
【发布时间】:2019-10-20 13:01:33
【问题描述】:

我有一列日期时间,需要将其中几个值更改为新的日期时间。当我使用 df.loc[indices, 'col'] = new_datetimes 设置值时,未受影响的值被强制为 int,而新的设置值在日期时间中。如果我一次设置一个值,则不会发生类型强制。

为了说明,我创建了一个只有一列的示例 df。

df = pd.DataFrame([dt.datetime(2019,1,1)]*5)
df.loc[[1,3,4]] = [dt.datetime(2019,1,2)]*3
df

这会产生以下结果: output

如果我单独更改索引 1、3、4:

df = pd.DataFrame([dt.datetime(2019,1,1)]*5)
df.loc[1] = dt.datetime(2019,1,2)
df.loc[3] = dt.datetime(2019,1,2)
df.loc[4] = dt.datetime(2019,1,2)
df

我得到正确的输出: output

建议在设置之前将列表转换为 numpy 数组,这确实解决了问题。但是,如果您尝试使用 numpy 数组设置多个列(其中一些不是日期时间),则问题再次出现。

在此示例中,数据框有两列,我尝试设置这两列。

df = pd.DataFrame({'dt':[dt.datetime(2019,1,1)]*5, 'value':[1,1,1,1,1]})
df.loc[[1,3,4]] = np.array([[dt.datetime(2019,1,2)]*3, [2,2,2]]).T
df

这给出了以下输出: output

有人可以解释导致强制的原因以及如何防止它这样做吗?我编写的使用它的代码是一个多月前编写的,并且过去运行得很好,这可能是关于未来版本的熊猫弃用某些功能的警告之一吗?

非常感谢您对正在发生的事情进行解释,因为我编写了可能使用类似功能的其他代码,希望确保一切按预期工作。

【问题讨论】:

  • 根据我尝试使用数据框而不是列表/数组设置的建议,它设置了两列而没有强制。 df.loc[[1,3,4]] = pd.DataFrame({'dt':[dt.datetime(2019,1,1)]*3, 'value':[2,2,2]}, index=[1,3,4]) 我想我会回到我写的代码并在设置之前将所有数组转换为数据帧。有谁知道不使用数据帧时强制的原因?
  • 您以不必要的方式分配值。 df.loc[[1,3,4]] = dt.datetime(2019,1,2), 2 返回正确的输出而不做任何更改。使用 .loc 如果它们都将更改为相同的输出,则无需匹配输入的长度。
  • 第二件事:1546300800000000000实际上是2019/1/1作为int的表示。 pd.to_datetime(1546300800000000000) 您可以看到将其转换回其日期时间格式。由于您设置它的方式,它将它转换为一个对象,并将 dt 转换为 int 版本。
  • 我想我应该让示例变得更复杂。为方便起见,我为三行设置了相同的值,但在实际应用程序中,行是不同的。我知道 int 实际上代表日期时间。令我困惑的是为什么 df.loc[1,3,4] = array 会导致强制,而 df.loc[1,3,4] = dataframe type 不会。

标签: pandas datetime slice


【解决方案1】:

w-m 提出的解决方案比 结果列也有时间部分(它没有 之前)。

我也有这样的说法,DataFrames 是 tables 而不是 Series, 所以他们有列,每个都有它的名字,这是一个坏习惯 依赖于默认的列名(连续的数字)。

所以我提出另一种解决方案,解决上述两个问题:

创建我执行的源 DataFrame:

df = pd.DataFrame([dt.datetime(2019, 1, 1)]*5, columns=['c1'])

请注意,我为唯一的列提供了名称。

然后我创建了另一个 DataFrame:

df2 = pd.DataFrame([dt.datetime(2019,1,2)]*3, columns=['c1'], index=[1,3,4])

它包含您在 loc 中使用的“新”日期和数字 我设置为 index(同样使用相同的列名)。

然后,要更新 df,请使用(毫不奇怪)df.update

df.update(df2)

这个函数执行就地更新,所以如果你print(df),你会得到:

          c1
0 2019-01-01
1 2019-01-02
2 2019-01-01
3 2019-01-02
4 2019-01-02

如您所见,在索引 1、3 和 4 下,您有新的日期 和以前一样,没有时间部分

【讨论】:

  • 使用数据框设置有效。我并不真正关心时间部分。问题是它把我的日期时间列变成了一列整数和日期时间。
【解决方案2】:

[dt.datetime(2019,1,2)]*3 是一个 Python 对象列表。这个特定的列表恰好只包含日期时间,但 Pandas 似乎没有认识到这一点,并将其视为原样 - 任何类型的对象的列表。

如果将其转换为类型化数组,那么 Pandas 将保持该列的原始 dtype 不变:

df.loc[[1,3,4]] = np.asarray([dt.datetime(2019,1,2)]*3)

我希望此解决方法对您有所帮助,但您可能仍想向 Pandas 提交错误。我没有解释为什么在第一个输出示例中应该将日期时间对象强制转换为整数。

【讨论】:

  • 谢谢,如果我只更改日期时间列,将其转换为数组确实有效。问题在于,在实际代码中,我使用 numpy 数组设置了多个列(其中之一是日期时间)。我将更新问题以包含此案例。
猜你喜欢
  • 2015-12-03
  • 2019-07-18
  • 2014-08-15
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
相关资源
最近更新 更多