将二维 numpy 数组转换为字符串

A B*_*A B 4 python arrays string numpy delimiter

我是 Python 新手,正在尝试转换 2d numpy 数组,例如:

a=numpy.array([[191.25,0,0,1],[191.251,0,0,1],[191.252,0,0,1]])
Run Code Online (Sandbox Code Playgroud)

到一个字符串,其中列条目由一个分隔符 '\t' 分隔,行由另一个分隔符 '\n' 分隔,控制每列的​​精度,以获得:

b='191.250\t0.00\t0\t1\n191.251\t0.00\t0\t1\n191.252\t0.00\t0\t1\n'
Run Code Online (Sandbox Code Playgroud)

首先,我通过以下方式创建数组:

import numpy as np

col1=np.arange(191.25,196.275,.001)[:, np.newaxis]
nrows=col1.shape[0]

col2=np.zeros((nrows,1),dtype=np.int)
col3=np.zeros((nrows,1),dtype=np.int)
col4=np.ones((nrows,1),dtype=np.int)

a=np.hstack((col1,col2,col3,col4))
Run Code Online (Sandbox Code Playgroud)

然后我通过以下两种方法之一生成 b:

方法一:

b=''
for i in range(0,a.shape[0]):
    for j in range(0,a.shape[1]-1):
        b+=str(a[i,j])+'\t'
    b+=str(a[i,-1])+'\n'
b
Run Code Online (Sandbox Code Playgroud)

方法二:

b=''
for i in range(0,a.shape[0]):
    b+='\t'.join(['%0.3f' %x for x in a[i,:]])+'\n'
b
Run Code Online (Sandbox Code Playgroud)

但是,我猜有更好的方法来生成 a 和 b。我正在寻找最有效的方法(即内存、时间、代码紧凑性)来创建 a 和 b。


跟进问题

谢谢迈克,

b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)+'\n'
Run Code Online (Sandbox Code Playgroud)

为我工作,但我有一些后续问题(这不适合评论部分):

  1. 虽然这更紧凑,但速度是否与执行嵌套 for 循环相同,因为这似乎在括号内发生?
  2. 我知道 x 和 y 是 y 的 2 个维度上的迭代器,但是,Python 如何“知道”它们以及它们应该迭代哪些维度?例如,在 Matlab 中,必须明确说明这些事情。
  3. 有没有办法独立设置每列的精度(例如,我想要前三列的 %0.3f 和最后一列的 %0.0f)?
  4. 有没有一种简单的方法来做相反的过程——即给定 b,产生 a?我想出了两种方法:

方法一

y=b.split('\n')[:-1]
z=[y[i].split('\t') for i in range(0,len(y))]
a=numpy.array(z,dtype=float)
Run Code Online (Sandbox Code Playgroud)

方法二

import re
a=numpy.array(filter(None,re.split('[\n\t]+',b)),dtype=float).reshape(-1,4)
Run Code Online (Sandbox Code Playgroud)

有没有更好的办法?

Mik*_*ler 6

解决方案

一个单线将做:

b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
Run Code Online (Sandbox Code Playgroud)

使用一个更简单的例子:

>>> a = np.arange(25, dtype=float).reshape(5, 5)
>>> a
array([[  0.,   1.,   2.,   3.,   4.],
       [  5.,   6.,   7.,   8.,   9.],
       [ 10.,  11.,  12.,  13.,  14.],
       [ 15.,  16.,  17.,  18.,  19.],
       [ 20.,  21.,  22.,  23.,  24.]])
Run Code Online (Sandbox Code Playgroud)

这个:

b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
print(b)
Run Code Online (Sandbox Code Playgroud)

打印这个:

0.000   1.000   2.000   3.000   4.000
5.000   6.000   7.000   8.000   9.000
10.000  11.000  12.000  13.000  14.000
15.000  16.000  17.000  18.000  19.000
20.000  21.000  22.000  23.000  24.000
Run Code Online (Sandbox Code Playgroud)

解释

您已经在第二种方法中使用了列表推导式。这里我们有一个生成器表达式,它看起来就像一个列表推导式。唯一的语法区别是[]被替换为()。一个发电机表达不生成列表,但手中所谓的发生器join。最后它具有相同的效果,但跳过了构建此中间列表的步骤。

for在这样的表达式中可以有多个,这使得它嵌套。这个:

b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
Run Code Online (Sandbox Code Playgroud)

相当于:

res = []
for y in a:
    res.append('\t'.join('%0.3f' %x for x in y))
b = '\n'.join(res)
Run Code Online (Sandbox Code Playgroud)

表现

%%timeit在 IPython Notebook 中使用:

%%timeit
b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)

10 loops, best of 3: 42.4 ms per loop


%%timeit
b=''
for i in range(0,a.shape[0]):
    for j in range(0,a.shape[1]-1):
        b+=str(a[i,j])+'\t'
    b+=str(a[i,-1])+'\n'

10 loops, best of 3: 50.2 ms per loop


%%timeit
b=''
for i in range(0,a.shape[0]):
    b+='\t'.join(['%0.3f' %x for x in a[i,:]])+'\n'

10 loops, best of 3: 43.8 ms per loop
Run Code Online (Sandbox Code Playgroud)

看起来它们的速度都差不多。实际上,它+=是在 CPython 中优化的。否则,它会比join()方法慢得多。其他Python实现,如Jython或PyPy可以显示更大的时间差,可以使join()相比要快得多+=