在 Numpy 数组中存储浮点数的高速和低内存方式

High-speed and low-memory way to store a float number inside a Numpy array

提问人:DazzRick 提问时间:8/7/2023 最后编辑:DazzRick 更新时间:8/8/2023 访问量:107

问:

我有这个数字:.我想将其保存在 Numpy 数组中,我认为虽然位数较低,但它仍然更好。这是对的吗?19576.4125

我试图在一半和一人中保存,但我不知道为什么它会改变数字。

  • 我的号码:19576.4125
  • 半:19580.0
  • 单:19576.412

这个数字是由我创建的用于访问浮点数的方法生成的。我可以使用时间戳,但我不需要秒和毫秒,所以我尝试创建自己的方法,只保存日期、小时和分钟。(我的数据库不接受 s 和 s)。datetimedatetimetimedelta

这是我的生成器方法:

from datetime import datetime


def get_timestamp() -> float:
    now = datetime.now()
    now.replace(microsecond=0, second=0)
    _1970 = datetime(1970, 1, 1, 0, 0, 0)
    td = now - _1970
    days = td.days
    hours, remainder = divmod(td.seconds, 3600)
    minutes, second = divmod(remainder, 60)
    timestamp = days + hours / 24 + minutes / 1440
    return round(timestamp, 4)

我如何创建数组:

from numpy import array, half, single


__td = get_timestamp()
print(__td)
__array = array([__td], dtype=half)
print(type(__array[0]))
print(__array[0])
__array = array([__td], dtype=single)
print(type(__array[0]))
print(__array[0])

已编辑 08/07 11h02 AM

您好,这样的评论说,我认为这个数字不能保存在一半或单一类型中。那么,如何以更好的性能保存这个数字呢?最好像 int 并乘以 10000、float64 或字符串一样保存?

而不是,我不想要更好的方法来保存这个具有更好性能的浮点数。但感谢您的其他回复。datetime

python 数组 numpy 性能 浮点

评论

3赞 Reinderien 8/7/2023
它改变了数字,因为当你扔掉数字的位时,你就是在浪费精度。
0赞 Reinderien 8/7/2023
这听起来像是过早的优化。只需使用 ,并研究文档即可。datetime64[m]
1赞 Homer512 8/7/2023
这回答了你的问题吗?浮点数学坏了吗?
0赞 DazzRick 8/7/2023
@Reinderien所以我不能像浮点一样保存这个数字?因为我说,我的数据库不接受日期时间,所以我只能用时间戳保存,而且时间戳不必要地最大。因为这个我创建了这个方法
0赞 DazzRick 8/7/2023
@Homer512 是的,它回答了我的疑问。我将编辑我的问题

答:

1赞 Suraj Shourie 8/7/2023 #1

我觉得你的标题问题和正文是不同的。 如果你的目标是制作一个函数,使“日期时间转到浮点数”,并可能稍后返回日期时间,你可以使用这种方法作为替代方法:

import datetime
# convert to a float timestamp
ts = datetime.datetime.now().timestamp()
# convert back to datetime format
datetime.datetime.fromtimestamp(ts)
1赞 hpaulj 8/8/2023 #2

我修改了您的函数以采用时间温度

In [48]: def get_timestamp(now) -> float:
    ...:     #now = datetime.now()
    ...:     now.replace(microsecond=0, second=0)
   ...
    ...:     return round(timestamp, 4)
    ...:     

并列出了日期:

In [49]: alist = [datetime.now() for _ in range(1000)]

In [50]: timeit alist = [datetime.now() for _ in range(1000)]
885 µs ± 2.27 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

并定时你的函数,以创建一个数组:

In [51]: arr = np.array([get_timestamp(d) for d in alist])

In [52]: timeit arr = np.array([get_timestamp(d) for d in alist])
7.7 ms ± 16.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [53]: arr.nbytes
Out[53]: 8000

并做了同样的事情,但使用 numpy 自己转换为 8 字节元素:

In [54]: barr = np.array(alist,dtype='datetime64[m]')

In [55]: barr.nbytes
Out[55]: 8000

In [56]: timeit barr = np.array(alist,dtype='datetime64[m]')
7.87 ms ± 38.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

所以转换时间基本相同。因此,从计算和记忆来看,您的函数同样出色。

另存为 4 字节元素(float 或 int)会减少内存使用,但除非您遇到数百万个值的内存错误,否则这种努力很少值得。

datetime64已经完成了两种方式的转换。我想界面也很好,尽管似乎有自己的日期时间格式和技巧。毕竟,它是为处理时间序列而设计的。pandaspandas

熊猫

In [64]: import pandas as pd

In [65]: df = pd.DataFrame({'a':arr, 'b':barr})

In [66]: df
Out[66]: 
              a                   b
0    19576.3799 2023-08-07 09:07:00
1    19576.3799 2023-08-07 09:07:00
2    19576.3799 2023-08-07 09:07:00
3    19576.3799 2023-08-07 09:07:00
4    19576.3799 2023-08-07 09:07:00
..          ...                 ...
995  19576.3799 2023-08-07 09:07:00
996  19576.3799 2023-08-07 09:07:00
997  19576.3799 2023-08-07 09:07:00
998  19576.3799 2023-08-07 09:07:00
999  19576.3799 2023-08-07 09:07:00

[1000 rows x 2 columns]

In [67]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype        
---  ------  --------------  -----        
 0   a       1000 non-null   float64      
 1   b       1000 non-null   datetime64[s]
dtypes: datetime64[s](1), float64(1)
memory usage: 15.8 KB

有趣的是,如果我将时间戳列表直接保存到数据帧中,它会更快

In [81]: df = pd.DataFrame({'c':alist})

In [82]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 1 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   c       1000 non-null   datetime64[ns]
dtypes: datetime64[ns](1)
memory usage: 7.9 KB

In [83]: timeit df = pd.DataFrame({'c':alist})
5.29 ms ± 22.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)