【问题标题】:Pandas v0.13.0: Setting DataFrame values of type datetime64[ns]Pandas v0.13.0:设置 datetime64[ns] 类型的 DataFrame 值
【发布时间】:2014-01-28 19:51:51
【问题描述】:

我最近将 Pandas 更新到 v0.13.0,它似乎引入了日期时间类型数据的问题。

让我们以这个例子为例,我们有一个数据框,其中一列 datetime64[ns] 和一列 int32。

import pandas as pd
import numpy as np

t  = pd.date_range('2000-01-01','2000-01-20')        
v  = np.arange(0,len(t))
df = pd.DataFrame({'date':t,'val':v})

首先,让我们将每一列设置为相同数据类型的标量值。

# SETTING SCALAR OF SAME TYPE
df.loc[:,'val']  = v[0] # Works fine
df.loc[:,'date'] = t[0] # Works fine

Pandas 正确地广播数据。任何一列都没有问题。

其次,让我们尝试用不同数据类型的标量替换:

# SETTING SCALAR, BUT OF DIFFERENT DTYPE
df.loc[:,'val']  = t[0] # Works fine
df.loc[:,'date'] = v[0] # Does not work?

虽然第一次操作成功,但第二次给出错误: "ValueError: 新类型与数组不兼容。"

第三,让我们尝试用一个数据向量替换每一列(不改变数据类型):

df = pd.DataFrame({'date':t,'val':v})

# SETTING VECTOR
df.loc[:,'val']  = v * 2 # Works fine
df.loc[:,'date'] = t.shift(365) # Does not work?

再次,第一个操作有效。但第二次操作失败,出现错误: "ValueError: 多元素数组的真值不明确。使用a.any() 或a.all()"

有人知道这里发生了什么吗?这可能是两个不同的问题。感谢您的帮助!

编辑:感谢 Jeff 为上述问题提供正确答案。然而,他的回答确实提出了一个(希望如此)最后一个问题:

如何分配给 DataFrame 的子集,其中子集跨越多行和多列,并且至少有一列是 datetime64 类型?

例如:

t  = pd.date_range('2000-01-01','2000-01-20')        
v  = np.arange(0,len(t))
df = pd.DataFrame({'date':t,'val':v,'val2':v})

# USING LABELS
df.loc[4:7,['val','val2']] = df.loc[4:7,['val','val2']] # Works fine
df.loc[4:7,['date','val']] = df.loc[4:7,['date','val']] # Does not work?

# USING ROW SLICE
df[4:7] = df[4:7]                                       # Does not work?

# USING BOOLEAN ROW MASK
mask = np.array([True] * len(df))
mask[[1,4,8]] = False
df[mask] = df[mask]                                     # Does not work?

虽然 Jeff 使用 df[col] = val 而不是 df.loc[:,col] = val 的解决方案正确解决了我原来的问题(列分配),但它对基于行(或行 x 列)没有帮助-based) 分配。*

  • 除非你转置 df.T[[4,5,6]] = df.T[[4,5,6]],但这似乎是作弊...

谢谢。

【问题讨论】:

  • 原来最后一个问题是由于一个错误,该错误将在即将发布的版本中修复。

标签: python datetime numpy pandas


【解决方案1】:

你操作是否直接作为列设置。

In [40]: df['date'] = v[0]

In [41]: df
Out[41]: 
    date  val
0      0    0
1      0    1
2      0    2
3      0    3
4      0    4
5      0    5
6      0    6
7      0    7
8      0    8
9      0    9
10     0   10
11     0   11
12     0   12
13     0   13
14     0   14
15     0   15
16     0   16
17     0   17
18     0   18
19     0   19

[20 rows x 2 columns]

In [42]: df = pd.DataFrame({'date':t,'val':v})

In [43]: df['date'] = t.shift(365)

In [44]: df
Out[44]: 
         date  val
0  2000-12-31    0
1  2001-01-01    1
2  2001-01-02    2
3  2001-01-03    3
4  2001-01-04    4
5  2001-01-05    5
6  2001-01-06    6
7  2001-01-07    7
8  2001-01-08    8
9  2001-01-09    9
10 2001-01-10   10
11 2001-01-11   11
12 2001-01-12   12
13 2001-01-13   13
14 2001-01-14   14
15 2001-01-15   15
16 2001-01-16   16
17 2001-01-17   17
18 2001-01-18   18
19 2001-01-19   19

[20 rows x 2 columns]

通过像df.loc[:,'date'] 这样的操作看起来很相似。但是您实际上要说的不是用右侧的内容替换此列,而是使用行掩码覆盖(在这种情况下恰好为空)。 dtype 转换未在此处完成,因为您可能会执行非常昂贵的操作。

当您只是设置一个新列时,更喜欢直接的 setitem df[col] = val

这不是一个错误,而是一个深思熟虑的选择;我想我会为此写一个文档说明,因为这是我在 w.r.t. 看到的第二个问题。对此,我想这有点令人困惑。

【讨论】:

  • 嗨,杰夫,感谢您的帮助。 1) 是否存在不一致,因为 df.loc[:,col] 适用于 dtype int、float 等但不适用于日期时间的列? (为什么要区别对待日期时间?) 2)好的,所以 df[col] = val 语法适用于设置列值(和更改 dtype)。但是,如果我需要设置新行呢?通常我会做 df.loc[rows,:] = val。但是,例如,df.loc[7:9] = df.loc[7:9] 给了我“真值”ValueError。 3) 而且,作为 2) 的扩展,如果我想做一个 df 的 2D 块,比如说 df.loc[4:5,['date','val']] = 100?非常感谢。
  • 不,您不会那样设置新行,请使用追加。你需要研究索引部分:pandas.pydata.org/pandas-docs/dev/indexing.html,有很多非常深思熟虑的选择(并不是所有都完全模仿 numpy)
  • 好的,会的。感谢您的帮助。
  • as 2 您的问题 1)它确实适用于日期时间,只是您分配了一个 0,即 1970-1-1,但您正在覆盖一部分数据(它恰好是整个切片,但这就是你要求的)。
  • 另外,如果我不清楚,我的 df.loc[7:9] = val 示例的目的不是追加行,而是更改现有行的内容(带有索引= 7 到 9)。
猜你喜欢
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-01
  • 2015-05-26
  • 2019-12-12
  • 2019-01-20
相关资源
最近更新 更多