我最近将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列)没有帮助分配。*
谢谢。
答案 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.对此,我猜它有点令人困惑。