我的目的:因为要从数据库读写包含时间、字符的数据并快速分析处理,我想把结构化的包含时间、字符数据的numpy自定义类型数据放入用NUMBA装饰的python函数中计算。
我的问题:进行了如下四种相关测试都报错
#####测试1,无法创建包含时间类型的NUMPY自定义数据类型
t1 = np.dtype([('age', int), ('date','datetime64')])
x = np.array([(1,''),(2,'2018-05-08')],dtype=t1)
###测试2,把包含时间数据的DF转换为NUMPY,再放入用NUMBA装饰的函数中,也不行。
a1=np.array([1,2,3])
a2=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='datetime64')
df =pd.DataFrame({'a1':a1,'a2':a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
###测试3,先创建包含时间数据的DF,再把DF转为NUMPY,再放入用NUMBA装饰的函数中,也不行,
a1=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='datetime64')# 把
a2=np.array([1,2,3])
df =pd.DataFrame({'a1':a1,'a2':a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
###测试4,先创建包含字符数据的DF,再把DF转为NUMPY,再放入用NUMBA装饰的函数中,也不行,
a1=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='str')
a2=np.array([1,2,3])
df = pd.DataFrame({'a1':a1,'a2':a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
基于Monster 组和GPT的调写:
测试1:无法创建包含时间类型的NumPy自定义数据类型
在这个测试中,您试图创建一个包含时间类型的NumPy自定义数据类型。但是,使用空字符串表示缺失值不是一种常见的做法。您可以使用numpy.datetime64('NaT')来表示缺失的日期时间值。以下是一个更新后的示例代码:
import numpy as np
t1 = np.dtype([('age', int), ('date','datetime64[D]')]) # 用 datetime64[D] 表示日期时间
x = np.array([(1, np.datetime64('NaT')), (2, np.datetime64('2018-05-08'))], dtype=t1)
测试2、3、4:
在测试2、3和4中,您将数据框转换为NumPy数组,然后将其传递给用Numba装饰的函数。但是,Numba需要在函数定义之前确定输入数据类型,因此在使用Numba之前,必须明确指定数组的数据类型。这可以通过传递NumPy数组的dtype参数来完成。
以下是测试2、3和4的更新示例代码:
import numpy as np
import pandas as pd
from numba import njit
# 测试2
a1 = np.array([1, 2, 3])
a2 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='datetime64')
df = pd.DataFrame({'a1': a1, 'a2': a2})
x = df.values.astype([('a1', np.int64), ('a2', 'datetime64[D]')]) # 显式指定数据类型
@njit()
def test(x):
pass
test(x)
# 测试3
a1 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='datetime64')
a2 = np.array([1, 2, 3])
df = pd.DataFrame({'a1': a1, 'a2': a2})
x = df[['a2', 'a1']].to_records(index=False).astype([('a2', np.int64), ('a1', 'datetime64[D]')]) # 显式指定数据类型
@njit()
def test(x):
pass
test(x)
# 测试4
a1 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='str')
a2 = np.array([1, 2, 3])
df = pd.DataFrame({'a1': a1, 'a2': a2})
x = df.values.astype([('a1', 'U19'), ('a2', np.int64)]) # 显式指定数据类型
@njit()
def test(x):
pass
test(x)
对于第一个问题,将numpy自定义类型数据放入NUMBA装饰的python函数中计算,可以考虑使用NUMBA中的结构体定义和结构体数组。具体代码如下:
import numpy as np
from numba import jit, types, struct
# 定义自定义数据类型
my_dtype = np.dtype([('time', 'datetime64[s]'), ('name', 'S10'), ('value', 'f4')])
# 定义结构体类型
my_struct = struct([('time', types.NPDatetime('s')), ('name', types.string), ('value', types.float32)])
# 将numpy数组转换为结构体数组
@jit(nopython=True)
def to_struct_array(arr):
n = arr.shape[0]
out = np.empty(n, dtype=my_struct)
for i in range(n):
out[i] = (np.datetime64(arr[i]['time']), arr[i]['name'].decode(), arr[i]['value'])
return out
# 在NUMBA装饰的函数中使用结构体数组
@jit(nopython=True)
def process_data(arr):
struct_arr = to_struct_array(arr)
# 对结构体数组进行计算
...
对于第二个问题,可以先定义自定义数据类型,然后使用np.frombuffer()或np.fromfile()读取二进制文件或内存块中的数据。具体代码如下:
import numpy as np
# 定义自定义数据类型
my_dtype = np.dtype([('time', 'datetime64[s]'), ('name', 'S10'), ('value', 'f4')])
# 从二进制文件中读取数据
with open('data.bin', 'rb') as f:
data = np.frombuffer(f.read(), dtype=my_dtype)
# 从内存块中读取数据
data = np.frombuffer(memory_block, dtype=my_dtype)
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
针对测试1,numpy中似乎不能使用datetime64类型作为dtype的元素类型。您可以使用numpy中的string类型或者numpy的void类型作为代替。例如:
t1 = np.dtype([('age', int), ('date','S10')])
x = np.array([(1,''),(2,'2022-01-01')],dtype=t1)
或者:
t1 = np.dtype([('age', int), ('date', 'V10')])
x = np.array([(1, None),(2, np.datetime64('2022-01-01'))],dtype=t1)
针对测试2和测试3,即使您已经使用pandas的DataFrame把时间格式数据转换成np.datetime64类型了,也不代表@njit装饰器可以很好地支持时间类型数据。因为NUMBA需要在运行之前就知道所有参数的类型和大小来进行字节码编译。在这种情况下,一种解决方法是:在测试2和测试3中,把时间类型数据分开处理并分别传递给被装饰函数(测试4同理处理字符数据)。例如:
# 测试2
a1=np.array([1,2,3])
a2=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='datetime64')
@njit
def test(a1, a2):
# do something
pass
test(a1, a2.astype('datetime64'))
# 测试3
a1=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='datetime64')
a2=np.array([1,2,3])
@njit
def test(a1, a2):
# do something
pass
test(a1.astype('datetime64'), a2)
# 测试4
a1=np.array(['2020-03','2020-03-08','2020-03-08 20:00'],dtype='str')
a2=np.array([1,2,3])
@njit
def test(a1, a2):
# do something
pass
test(a1, a2)
请注意,测试2中,我们使用astype('datetime64')
将类型转换为NUMPY的datetime64类型。这样做可以确保NUMBA能够识别数组类型并执行适当的操作。
希望这些对您有帮助!
如果我的回答解决了您的问题,请采纳!
测试1
在你提供的代码中,使用了自定义的 NumPy 数据类型 t1,其中包含了两个字段 'age' 和 'date'。在 'date' 字段中,你指定了其数据类型为 datetime64,但是在创建 NumPy 数组 x 的过程中,第二个元素的日期值却是个空字符串,这将导致创建新数组时出现错误:即无法将空字符串转换成 datetime64 类型。
要解决这个问题,你可以在创建 NumPy 数组 x 时,对第二个元素的空值进行特殊处理。具体来说,你可以将空字符串改为 NaT(Not a Time)值,表示无效的时间戳。这样就能成功创建包含时间类型的自定义数据类型了。
下面是修改后的代码:
t1 = np.dtype([('age', int), ('date','datetime64')])
x = np.array([(1, np.datetime64('NaT')), (2, np.datetime64('2018-05-08'))], dtype=t1)
在新的代码中,我们将空字符串替换成了 np.datetime64('NaT')。这样就能成功创建包含时间类型的自定义数据类型,并创建 NumPy 数组了。
测试2
你创建了一个包含时间数据的 Pandas DataFrame,并试图将其转换为 NumPy 数组,然后将该数组传递给一个使用 @njit 装饰器修饰的 Numba 函数。然而,你遇到了转换数组时出现的错误,导致 Numba 函数不能正确处理输入数据。
问题出在将时间数据转换为 NumPy 数组时,需要注意时间类型的精度。Pandas DataFrame 中的日期时间数据类型是 'datetime64[ns]',即纳秒级别的时间戳,而默认情况下,NumPy 的 datetime64 类型是以纳秒为单位储存时间的。因此,你需要将 Pandas DataFrame 中的时间数据转换成与 NumPy datetime64 类型匹配的精度,否则转换过程会失败。
下面是修改后的代码:
import numpy as np
import pandas as pd
from numba import njit
a1 = np.array([1, 2, 3])
a2 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='datetime64[ns]')
df = pd.DataFrame({'a1': a1, 'a2': a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
在新的代码中,我们将 Pandas DataFrame 中的 'datetime64' 数据类型转换成了 'datetime64[ns]' 精度,即与 NumPy 中的默认时间精度一致。此外,我们还将 Numba 函数的调用放在了最后一行,以避免出现未定义的变量错误。这样代码就能正确地将包含时间数据的 Pandas DataFrame 转换为 NumPy 数组,并将其作为参数传递给 Numba 函数。
测试3
问题出在将时间数据转换为 NumPy 数组时,需要注意时间类型的精度。在你的代码中,你将时间数据存储在第一列 'a1' 中,但是你没有指定时间的精度级别。因此,当你试图将 Pandas DataFrame 转换为 NumPy 数组时,程序无法推断出正确的时间精度级别,从而抛出了错误。
要解决这个问题,你应该在创建 Pandas DataFrame 时对时间数据的精度级别进行明确的指定。具体来说,你可以将 'datetime64' 按照所需的精度级别进行转换,再将其存储在 DataFrame 中。例如,如果你希望时间精度级别是纳秒,则可以将 'datetime64' 转换为 'datetime64[ns]'。
下面是修改后的代码:
import numpy as np
import pandas as pd
from numba import njit
a1 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='datetime64[ns]')
a2 = np.array([1, 2, 3])
df = pd.DataFrame({'a1': a1, 'a2': a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
测试4
要解决这个问题,你应该在创建 Pandas DataFrame 时对字符串数据类型进行明确的指定。具体来说,你可以将 'str' 按照所需的数据类型进行转换,再将其存储在 DataFrame 中。例如,如果你希望字符串数据类型为 Unicode,则可以将 'str' 转换为 'U'。
下面是修改后的代码:
import numpy as np
import pandas as pd
from numba import njit
a1 = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='U')
a2 = np.array([1, 2, 3])
df = pd.DataFrame({'a1': a1, 'a2': a2})
print(df.values)
print(df.dtypes)
@njit()
def test(x):
pass
test(df.values)
在新的代码中,我们将 Pandas DataFrame 中的 'str' 数据类型转换成了 'U',即指定数据类型为 Unicode。此外,我们还将 Numba 函数的调用放在了最后一行,以避免出现未定义的变量错误。这样代码就能正确地将包含字符串数据的 Pandas DataFrame 转换为 NumPy 数组,并将其作为参数传递给 Numba 函数。