首页 > 解决方案 > 使用 iloc 或 loc 将多列转换为日期时间

问题描述

我不确定这是否是预期的行为,但下面是一个示例数据框。

df = pd.DataFrame([['2020-01-01','2020-06-30','A'],
                    ['2020-07-01','2020-12-31','B']],
                        columns = ['start_date', 'end_date', 'field1'])

在升级到 pandas 版本之前1.3.4,我相信我能够像这样转换列 dtypes:

df.iloc[:,0:2] = df.iloc[:,0:2].apply(pd.to_datetime)

尽管似乎已将列转换为日期时间,

            start_date             end_date field1
0  2020-01-01 00:00:00  2020-06-30 00:00:00      A
1  2020-07-01 00:00:00  2020-12-31 00:00:00      B

dtypes 似乎仍然是对象:

start_date    object
end_date      object
field1        object

我知道我可以使用下面的代码做同样的事情,我只是想知道这是否是locand的预期行为iloc

df[['start_date', 'end_date']] = df[['start_date', 'end_date']].apply(pd.to_datetime)
start_date    datetime64[ns]
end_date      datetime64[ns]
field1                object

标签: pythonpandas

解决方案


此行为是1.3.0中引入的更改的一部分。

loc使用和设置值时尝试就地操作iloc

loc当使用or设置整列时iloc,pandas 将尝试将值插入现有数据中,而不是创建一个全新的数组。

这意味着如果新数组可以适合现有类型,iloc并且loc将尝试更改数组的 dtype :

import pandas as pd

df = pd.DataFrame({'A': [1.2, 2.3], 'B': [3.4, 4.5]})
print(df)
print(df.dtypes)
df.loc[:, 'A':'B'] = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
print(df)
print(df.dtypes)

输出:

     A    B
0  1.2  3.4
1  2.3  4.5
A    float64
B    float64
dtype: object
     A    B
0  1.0  3.0
1  2.0  4.0
A    float64
B    float64
dtype: object

相反: 设置时切勿原位操作frame[keys] = values

当使用新数组设置多个列时,frame[keys] = values将替换这些键的预先存在的数组,这些数组不会被覆盖(GH39510)。结果,列将保留值的 dtype,从不转换为现有数组的 dtype。

import pandas as pd

df = pd.DataFrame({'A': [1.2, 2.3], 'B': [3.4, 4.5]})
print(df)
print(df.dtypes)
df[['A', 'B']] = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
print(df)
print(df.dtypes)

输出:

     A    B
0  1.2  3.4
1  2.3  4.5
A    float64
B    float64
dtype: object
   A  B
0  1  3
1  2  4
A    int64
B    int64
dtype: object

考虑到这些变化,我们现在必须执行以下操作:

import pandas as pd

df = pd.DataFrame([['2020-01-01', '2020-06-30', 'A'],
                   ['2020-07-01', '2020-12-31', 'B']],
                  columns=['start_date', 'end_date', 'field1'])

cols = df.columns[0:2]
df[cols] = df[cols].apply(pd.to_datetime)
# or
# df[df.columns[0:2]] = df.iloc[:, 0:2].apply(pd.to_datetime)

print(df)
print(df.dtypes)

输出:

  start_date   end_date field1
0 2020-01-01 2020-06-30      A
1 2020-07-01 2020-12-31      B
start_date    datetime64[ns]
end_date      datetime64[ns]
field1                object
dtype: object

推荐阅读