numpy Pandas替换datetime列中的值而不更改datetime64数据类型

pobjuy32  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(104)

我有一个dataframe,其中我有一个datetime64[ns]数据类型列,我想应用一个标准,如果日期超过某个年份,它应该采用我提供的固定日期。就像“如果日期超过这个点,最大限度地到这个日期”
我注意到,如果我从任何datetime64[ns]列中选择一个元素,它的类型是pd.Timestamp,所以我想我应该传递具有相同数据类型的固定日期,以保留整个列的数据类型
但无论我如何传递固定日期(pd.Timestamp或as datetime.datetime),它总是将datetime64列转换为object数据类型,并以纳秒为单位给出一个历元。
我的问题是,如何使用np.where替换 Dataframe 中的某些值,如果它们满足条件而不改变原始列类型,假设插入的新值与列的类型相同。
举个例子

#generate some data
df=pd.DataFrame({'a':[datetime.now() for i in range(10)]})
#The previous line generated a column named a with datetime64[ns]
# data type if you look at df.dtypes

df.loc[0,'a']=datetime(2050,1,1)
#In the previous line I already substitued a value by directly
# accessing its index, and it does preserve the data type datetime64[ns].
# This is the data

a
0   2050-01-01 00:00:00.000000
1   2023-08-01 17:29:59.011984
2   2023-08-01 17:29:59.011984
3   2023-08-01 17:29:59.011984
4   2023-08-01 17:29:59.011984
5   2023-08-01 17:29:59.011984
6   2023-08-01 17:29:59.011984
7   2023-08-01 17:29:59.011984
8   2023-08-01 17:29:59.011984
9   2023-08-01 17:29:59.011984

#I want to top the date until today's date if the year exceeds the present year
df['a']=np.where(df['a'].dt.year>2023,datetime.now(),df['a'])
#In the previous line, I substitued values but accessing to them
#  conditionally with an np.where The result of this 
# changes column 'a' data type into integer and puts unix epochs,
# yet the inserted data looks like datetime, this is the output

    a
0   2023-08-01 17:31:48.560111
1   1690910999011984000
2   1690910999011984000
3   1690910999011984000
4   1690910999011984000
5   1690910999011984000
6   1690910999011984000
7   1690910999011984000
8   1690910999011984000
9   1690910999011984000

字符串

5vf7fwbs

5vf7fwbs1#

In [173]: from datetime import datetime
In [174]: df=pd.DataFrame({'a':[datetime.now() for i in range(10)]})
     ...: df.loc[0,'a']=datetime(2050,1,1)
In [175]: df
Out[175]: 
                           a
0 2050-01-01 00:00:00.000000
1 2023-08-01 22:01:32.599755
2 2023-08-01 22:01:32.599756
3 2023-08-01 22:01:32.599758
...
9 2023-08-01 22:01:32.599765
In [176]:  df.dtypes
Out[176]: 
a    datetime64[ns]
dtype: object
In [177]: df.loc[0,'a']
Out[177]: Timestamp('2050-01-01 00:00:00')
In [178]: type(_)
Out[178]: pandas._libs.tslibs.timestamps.Timestamp

字符串
因此,看起来pandas已经将datetime对象转换为np.datetime64[ns]值。当“提取”时,它显示Timestamp
提取为numpy数组:

In [181]: df['a'].values
Out[181]: 
array(['2050-01-01T00:00:00.000000000', '2023-08-01T22:01:32.599755000',
       '2023-08-01T22:01:32.599756000', '2023-08-01T22:01:32.599758000',
        ...],
      dtype='datetime64[ns]')


探索where,无需赋值:

In [182]: np.where(df['a'].dt.year>2023,datetime.now(),df['a'])
Out[182]: 
array([datetime.datetime(2023, 8, 1, 22, 4, 1, 660226),
       1690927292599755000, 1690927292599756000, 1690927292599758000,
       1690927292599759000, 1690927292599760000, 1690927292599761000,
       1690927292599762000, 1690927292599763000, 1690927292599765000],
      dtype=object)


wheredatatime64数组和datetime对象的值组合在一起,生成一个对象dtype数组。

In [183]: np.where(df['a'].dt.year>2023,datetime.now(),df['a'].values)


使用values没有什么区别。
但是让我们更多地看看datetime `对象:

In [184]: datetime.now()
Out[184]: datetime.datetime(2023, 8, 1, 22, 4, 45, 741794)
In [185]: np.datetime64(datetime.now())
Out[185]: numpy.datetime64('2023-08-01T22:05:10.714725')


现在,如果我们在两个参数中使用wheredatatime64元素:

In [187]: np.where(df['a'].dt.year>2023,np.datetime64(datetime.now()),df['a'])
Out[187]: 
array(['2023-08-01T22:06:06.657836000', '2023-08-01T22:01:32.599755000',
       '2023-08-01T22:01:32.599756000', '2023-08-01T22:01:32.599758000',
       ...],
      dtype='datetime64[ns]')


现在我们可以将其赋值回dataframe:

In [189]: df['b']=np.where(df['a'].dt.year>2023,np.datetime64(datetime.now()),df['a'])
In [190]: df
Out[190]: 
                           a                          b
0 2050-01-01 00:00:00.000000 2023-08-01 22:06:46.833972
1 2023-08-01 22:01:32.599755 2023-08-01 22:01:32.599755
2 2023-08-01 22:01:32.599756 2023-08-01 22:01:32.599756
3 2023-08-01 22:01:32.599758 2023-08-01 22:01:32.599758
...


因此,虽然简单地将datetime对象分配给dataframe单元格会强制转换为datetime64,但要使where也能工作,我们必须首先进行显式转换。

vxf3dgd4

vxf3dgd42#

这个问题的发生是因为你混合了pandas和numpy,它们对日期时间类型有不同的概念。你需要使用pandas来进行过滤:

df.loc[df['a'].dt.year>2023,'a'] = datetime.now()

字符串

lpwwtiir

lpwwtiir3#

您遇到的问题与使用np.where函数时的数据类型一致性有关。当您在单个列中混合不同的数据类型时,Pandas可能会将整个列提升为可以容纳所有值的更通用的数据类型,从而导致观察到的行为。
要实现在保留列的数据类型的同时有条件地更新值的目标,可以使用apply函数沿着一个自定义函数,该函数根据您的条件返回原始日期时间或固定日期。此方法将确保列的数据类型保持不变。
以下是您的操作方法:

import pandas as pd
from datetime import datetime

# Generate some data
df = pd.DataFrame({'a': [datetime.now() for i in range(10)]})

# Substitution function
def update_date(row):
    if row['a'].year > 2023:
        return datetime.now()
    return row['a']

# Apply the function to the column
df['a'] = df.apply(update_date, axis=1)

print(df)

字符串
这是输出:

a
0 2023-08-02 15:33:39.915189
1 2023-08-02 15:33:39.915189
2 2023-08-02 15:33:39.915189
3 2023-08-02 15:33:39.915189
4 2023-08-02 15:33:39.915189
5 2023-08-02 15:33:39.915189
6 2023-08-02 15:33:39.915189
7 2023-08-02 15:33:39.915189
8 2023-08-02 15:33:39.915189
9 2023-08-02 15:33:39.915189

相关问题