从numpy ndarray创建Python的datetime对象数组

3 投票
2 回答
13229 浏览
提问于 2025-04-17 02:45

我有一个numpy的ndarray,它里面有两列:一列是日期,比如2011-08-04,另一列是时间,比如19:00:00:081。

我该怎么把它们合并成一个包含日期时间对象的数组呢?现在它们在numpy数组里都是字符串形式。

2 个回答

2

要回答这个问题,如果你有一个两列的NumPy数组 a,你可以这样做:

b = numpy.array([datetime.datetime.strptime(s + t, "%Y-%m-%d%H:%M:%S:%f")
                 for s, t in a])

因为评论里提到原始数组 a 是用 genfromtxt() 创建的,所以你可能更好地在文本文件中把列合并起来,并定义一个合适的转换器(可以参考genfromtxt()converters 参数)。

编辑:如果这两列的类型分别是 S10S12,那么你可以稍微优化一下这个代码,因为你不需要明确地合并这两列:

a = numpy.array([("2011-08-04", "19:00:00:081"), 
                 ("2011-08-04", "19:00:00:181")], 
                dtype=[("", "S10"), ("", "S12")])
b = numpy.array([datetime.datetime.strptime(s, "%Y-%m-%d%H:%M:%S:%f")
                 for s in a.view("S22")])

操作 a.view("S22") 是很简单的,因为它并不会复制数据。如果你的数组真的很大,这个优化可能会很有用,尽管它的影响不是特别大。

8

如果在example.txt这个数据文件中,日期和时间的字符串是放在一列里,没有空格分隔,那么可以用genfromtxt把它转换成日期时间对象,像这样:

import numpy as np
import datetime as dt
def mkdate(text):
    return dt.datetime.strptime(text, '%Y-%m-%dT%H:%M:%S:%f')    
data = np.genfromtxt(
    'example.txt',
    names=('data','num','date')+tuple('col{i}'.format(i=i) for i in range(19)),
    converters={'date':mkdate},
    dtype=None)

如果直接使用example.txt,你可以这样形成想要的numpy数组:

import numpy as np
import datetime as dt
import csv

def mkdate(text):
    return dt.datetime.strptime(text, '%Y-%m-%d%H:%M:%S:%f')    

def using_csv(fname):
    desc=([('data', '|S4'), ('num', '<i4'), ('date', '|O4')]+
          [('col{i}'.format(i=i), '<f8') for i in range(19)])
    with open(fname,'r') as f:
        reader=csv.reader(f,delimiter='\t')
        data=np.array([tuple(row[:2]+[mkdate(''.join(row[2:4]))]+row[4:])
                       for row in reader],
                      dtype=desc)
    # print(mc.report_memory())        
    return data

在numpy数组中合并两列可能会比较慢,特别是当数组很大的时候。这是因为合并操作就像调整大小一样,需要为新的数组分配内存,并把原数组的数据复制到新数组中。所以我觉得直接形成正确的numpy数组是值得尝试的,而不是分步骤进行(先形成一个部分正确的数组,再合并两列)。


顺便说一下,我测试过上面的csv代码和合并两列的速度(下面的)。从csv形成一个单一数组的速度更快(而且内存使用差不多):

import matplotlib.cbook as mc
import numpy as np
import datetime as dt

def using_genfromtxt(fname):
    data = np.genfromtxt(fname, dtype=None)

    orig_desc=data.dtype.descr
    view_desc=orig_desc[:2]+[('date','|S22')]+orig_desc[4:]
    new_desc=orig_desc[:2]+[('date','|O4')]+orig_desc[4:]

    newdata = np.empty(data.shape, dtype=new_desc)
    fields=data.dtype.names
    fields=fields[:2]+fields[4:]
    for field in fields:
        newdata[field] = data[field]

    newdata['date']=np.vectorize(mkdate)(data.view(view_desc)['date'])
    # print(mc.report_memory())

    return newdata  

# using_csv('example4096.txt')
# using_genfromtxt('example4096.txt')

example4096.txtexample.txt是一样的,只是重复了4096次。它大约有12K行。

% python -mtimeit -s'import test' 'test.using_genfromtxt("example4096.txt")'
10 loops, best of 3: 1.92 sec per loop

% python -mtimeit -s'import test' 'test.using_csv("example4096.txt")'
10 loops, best of 3: 982 msec per loop

撰写回答