numpy save an array of different types to a text f

2020-02-02 01:59发布

问题:

Say I have the following numpy structured array:

>>> a = numpy.array((1, 2.0, 'buckle_my_shoe'),dtype=('i4,f8,a14')) 
array((1, 2.0, 'buckle_my_shoe'), 
  dtype=[('f0', '<i4'), ('f1', '<f8'), ('f2', 'S14')])

and I want to save it to a single space or tab delimited row in a text file. If the array were all of the same type I could use numpy.savetxt('myfile.dat,myarray,newline=" "). However, this seems to not like mixed data types/structured arrays, for example:

file('myfile.dat', 'a')
numpy.savetxt('myfile.dat',a,newline=" ")

gives this error:

IndexError: tuple index out of range

Can anyone recommend a way of doing this?

回答1:

Edit: For whatever reason I can't seem to be able to leave this answer alone, so here's a cleaner version that doesn't use the csv module unnecessarily. For the record, @askewchan's answer is still better!

a = numpy.array([(1, 2.0, 'buckle_my_shoe'),
                 (3,4.0,'lock_the_door')],dtype=('i4,f8,a14'))
with open('test.txt','w') as f:
     f.write(' '.join([str(item) for sublist in a for item in sublist]))
print open('test.txt','r').read()

Output:

1 2.0 buckle_my_shoe 3 4.0 lock_the_door


回答2:

If you have a zero-d array like your example, then you can just do this:

b = np.array((1, 2.0, 'buckle_my_shoe'), 
         dtype=[('f0', '<i4'), ('f1', '<f8'), ('f2', 'S14')])

with open('myfile.dat','w') as f:
    for el in b[()]:
        f.write(str(el)+' ') # or `f.write(repr(el)+' ') to keep the quote marks

This works by accessing the elements of 0d arrays using [()]:

>>> b.ndim
0

>>> b[0]
IndexError: 0-d arrays cannot be indexed

>>> b[()]
(1, 2.0, 'buckle_my_shoe')

If you are using numpy arrays with zero dimensions regularly, in order to have the complex dtype, I might suggested the NamedTuple from collections.

>>> import collections
>>> A = collections.namedtuple('A', ['id', 'val', 'phrase'])
>>> a = A(1, 2.0, 'buckle_my_shoe')

>>> a
A(id=1, val=2.0, phrase='buckle_my_shoe')
>>> a.id
1
>>> a.val
2.0
>>> a.phrase
'buckle_my_shoe'

with open('myfile.dat','w') as f:
    for el in a:    
        f.write(repr(el)+' ')

If the array has more than one element:

a = np.array([(1, 2.0, 'buckle_my_shoe'),
              (3, 4.0, 'lock_the_door')],
        dtype=('i4, f8, a14'))

I'm not sure what exactly you want your file to look like. If you want the space-separated tuples, this is the best way I think:

with open('myfile.dat','w') as f:
    for row in a:
        f.write(repr(row)+' ')

which results in a file like:

(1, 2.0, 'buckle_my_shoe') (3, 4.0, 'lock_the_door')

Perhaps you wanted to have no commas or parentheses, in which case you can do:

with open('myfile.dat','w') as f:
    for row in a:
        for el in row:
            f.write(str(el)+' ')

which gives this file:

1 2.0 buckle_my_shoe 3 4.0 lock_the_door 

Use repr to keep the qutoes around the strings

with open('myfile.dat','w') as f:
    for row in a:
        for el in row:
            f.write(repr(el)+' ')

which gives this file:

1 2.0 'buckle_my_shoe' 3 4.0 'lock_the_door' 

Bonus: If your dtype has field names, you can print those too:

a.dtype.names = "index value phrase".split()
a.dtype
#dtype([('index', '<i4'), ('value', '<f8'), ('phrase', 'S14')])

with open('myfile.dat','w') as f:
    for name in a.dtype.names:
        f.write(name + ' ') # or write(repr(name)) to keep the quote marks
    for row in a:
        for el in row:
            f.write(repr(el)+' ')

Note, if you copy these files be warned I used 'w' not 'a', so that I could overwrite each one in my test cases.