为啥调用 '.values' 时 pd.Timestamp 会转换为 np.datetime64?

Posted

技术标签:

【中文标题】为啥调用 \'.values\' 时 pd.Timestamp 会转换为 np.datetime64?【英文标题】:Why is pd.Timestamp converted to np.datetime64 when calling '.values'?为什么调用 '.values' 时 pd.Timestamp 会转换为 np.datetime64? 【发布时间】:2020-03-04 01:35:21 【问题描述】:

访问DataFrame.values时,所有pd.Timestamp对象都被转换为np.datetime64对象,为什么?一个包含pd.Timestamp对象的np.ndarray可以存在,所以我不明白为什么总是会发生这种自动转换。

你知道如何预防吗?

小例子:

import numpy as np
import pandas as pd
from datetime import datetime

# Let's declare an array with a datetime.datetime object
values = [datetime.now()]
print(type(values[0]))
> <class 'datetime.datetime'>

# Clearly, the datetime.datetime objects became pd.Timestamp once moved to a pd.DataFrame
df = pd.DataFrame(values, columns=['A'])
print(type(df.iloc[0][0]))
> <class 'pandas._libs.tslibs.timestamps.Timestamp'>

# Just to be sure, lets iterate over each datetime and manually convert them to pd.Timestamp
df['A'].apply(lambda x: pd.Timestamp(x))
print(type(df.iloc[0][0]))
> <class 'pandas._libs.tslibs.timestamps.Timestamp'>

# df.values (or series.values in this case) returns an np.ndarray
print(type(df.iloc[0].values))
> <class 'numpy.ndarray'>

# When we check what is the type of elements of the '.values' array, 
# it turns out the pd.Timestamp objects got converted to np.datetime64
print(type(df.iloc[0].values[0]))
> <class 'numpy.datetime64'>


# Just to double check, can an np.ndarray contain pd.Timestamps?
timestamp = pd.Timestamp(datetime.now())
timestamps = np.array([timestamp])
print(type(timestamps))
> <class 'numpy.ndarray'>

# Seems like it does. Why the above conversion then?
print(type(timestamps[0]))
> <class 'pandas._libs.tslibs.timestamps.Timestamp'>

python:3.6.7.final.0

熊猫:0.25.3

numpy : 1.16.4

【问题讨论】:

【参考方案1】:

.values 背后的整个想法是:

返回 DataFrame 的 Numpy 表示。 [docs]

我发现 pd.Timestamp 然后“降级”为 dtype 是合乎逻辑的,它是 numpy 的本机。如果它不这样做,那么.values的目的是什么?

如果您确实想保留pd.Timestamp dtype,我建议您使用原始Series (df.iloc[0])。从.values uses np.ndarray 之后,我没有看到任何其他方式可以根据 Github 上的源进行转换。

【讨论】:

它似乎使用.to_numpy() 代替,正如文档所建议的那样,会产生强制某个dtype 的可能性,但这对我来说失败了(“TypeError:数据类型“pd.Timestamp”不理解") 但是为什么他们声明The dtype will be a lower-common-denominator dtype?如果系列只包含一种类型,为什么要转换它?我猜他们真的想强调 Numpy 表示。会不会是我使用了错误的功能?如何在不进行任何转换的情况下访问 DataFrame 的内部数据结构?否则,如何在不强制转换的情况下将 DataFrame 转换为 np.ndarray?我相信这就是.values 的目的。 我不认为它被转换为np.datetime64,因为这是较低的公分母dtype,而是因为pd.Timestamp 不是numpy 的一部分。具有 pandas 功能的向量是 Series 并将其转换为 numpy 数组会删除那些 pandas 功能。【参考方案2】:

找到了解决方法 - 使用 .array 而不是 .values (docs)

print(type(df['A'].array[0]))
> <class 'pandas._libs.tslibs.timestamps.Timestamp'>

这可以防止转换并让我可以访问我想要使用的对象。

【讨论】:

非常感谢。我发现 .values 函数有点违反直觉:我希望它只是访问系列中的值而不是转换为 Numpy 表示。 .array 正是我要找的,但对我来说,这又不是一种直观的语法:我希望能够以列表的形式访问这些值;例如:df['A'][0]. 对于此类索引,您可以使用.iat

以上是关于为啥调用 '.values' 时 pd.Timestamp 会转换为 np.datetime64?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在按值返回时总是调用复制构造函数

为啥初始化此类时不调用列表初始化?

为啥以这种方式使用 Alamofire 时没有发现任何价值?

为啥登录时 ["value":"tag1" 变成 [object Object]?

为啥 std::optional::value() &&;返回 &&?

为啥单击按钮时 $w("#input1").value 不更改? (蜡网站代码)