Pandas v0.13.0:设置datetime64 [ns]类型的DataFrame值

时间:2014-01-28 19:51:51

标签: python datetime numpy pandas

我最近将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()”

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

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

如何分配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列)没有帮助分配。*

  • 除非你转换df.T [[4,5,6]] = df.T [[4,5,6]],否则这似乎在作弊......

谢谢。

1 个答案:

答案 0 :(得分:2)

您是否直接进行列设置操作。

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']这样的事情看起来很相似。但你实际上所说的并不是用右边的内容替换这个列,而是使用行掩码覆盖(在这种情况下恰好是null)。这里没有进行dtype转换,因为您可能会进行非常昂贵的操作。

当您只是设置新列时,请优先选择直接的setitem df[col] = val

这不是一个错误,而是一个刻意的选择;我想我会写一篇关于这个的文档说明,因为这是我见过的第二个问题w.r.t.对此,我猜它有点令人困惑。