Сохранение и загрузка пользовательского dtype в / из текстового файла с numpy - PullRequest
0 голосов
/ 09 апреля 2020

Я ввел свой собственный тип данных и хочу снабдить его sh функциями сохранения / загрузки, которые будут работать с текстовыми файлами, но мне не удалось предоставить правильную строку fmt для numpy .savetxt (). Проблема возникает из-за того, что одним из полей моего dtype является кортеж (два числа с плавающей запятой в наивном примере ниже), который, как мне кажется, эффективно приводит к попытке сохранить 3D-объект с помощью savetxt ().

Его можно заставить работать только при сохранении числа с плавающей точкой как "% s" (но тогда я не могу их загрузить () в варианте 1 в коде) или при введении неэффективной функции my_repr () (вариант 2) ниже .

Я не могу поверить, что numpy не обеспечивает эффективного форматирования / сохранения / загрузки API для пользовательских типов. Кто-нибудь с идеей решить это красиво?

import numpy as np


def main():
    my_type = np.dtype([('single_int', np.int), 
                        ('two_floats', np.float64, (2,))])
    my_var = np.array(  [(1, (2., 3.)), 
                         (4, (5., 6.))
                        ],  
                        dtype=my_type)
    # Verification
    print(my_var)
    print(my_var['two_floats'])
    # Let's try to save and load it in three variants
    variant = 2
    if variant == 0:
        # the line below would not work: "ValueError: fmt has wrong number of % formats:  %d %f %f"
        np.savetxt('f.txt', my_var, fmt='%d %f %f')
        # so I don't even try to load
    elif variant == 1:
        # The line below does work, but saves floats between '[]' which makes them not loadable later
        np.savetxt('f.txt', my_var, fmt='%d %s')
        # lines such as "1 [2. 3.]" won't load, the line below raises an Exception
        my_var_loaded = np.loadtxt('f.txt', dtype=my_type)
    elif variant == 2:
        # An ugly workaround:
        def my_repr(o):
            return [(elem['single_int'], *elem['two_floats']) for elem in o]
        # and then the rest works fine:
        np.savetxt('f.txt', my_repr(my_var), fmt='%d %f %f')
        my_var_loaded = np.loadtxt('f.txt', dtype=my_type)
        print('my_var_loaded')
        print(my_var_loaded)

if __name__ == '__main__':
    main()

1 Ответ

1 голос
/ 09 апреля 2020
In [115]: my_type = np.dtype([('single_int', np.int),  
     ...:                         ('two_floats', np.float64, (2,))])                                   
In [116]: my_var = np.array(  [(1, (2., 3.)),  
     ...:                          (4, (5., 6.)) 
     ...:                         ],   
     ...:                         dtype=my_type)                                                       
In [117]: my_var                                                                                       
Out[117]: 
array([(1, [2., 3.]), (4, [5., 6.])],
      dtype=[('single_int', '<i8'), ('two_floats', '<f8', (2,))])

Прыжок прямо к шагу загрузки:

In [118]: txt = """1 2. 3. 
     ...: 4 5. 6."""                                                                                   
In [119]: np.genfromtxt(txt.splitlines(), dtype=my_type)                                               
Out[119]: 
array([(1, [2., 3.]), (4, [5., 6.])],
      dtype=[('single_int', '<i8'), ('two_floats', '<f8', (2,))])

Как я уже говорил, savetxt просто делает:

for row in my_var:
    f.write(fmt % tuple(row))

Так что мы должны, так или иначе другие, обходите или с базовым форматированием c Python %. Либо так, либо напишите наш собственный текстовый файл. В savetxt нет ничего волшебного. Это просто python.

===

Последние версии numpy включают функцию для "выравнивания" структурированного массива:

In [120]: import numpy.lib.recfunctions as rf                                                          
In [121]: arr = rf.structured_to_unstructured(my_var)                                                  
In [122]: arr                                                                                          
Out[122]: 
array([[1., 2., 3.],
       [4., 5., 6.]])
In [123]: np.savetxt('test.csv', arr, fmt='%d %f %f')                                                  
In [124]: cat test.csv                                                                                 
1 2.000000 3.000000
4 5.000000 6.000000
In [125]: np.genfromtxt('test.csv', dtype=my_type)                                                     
Out[125]: 
array([(1, [2., 3.]), (4, [5., 6.])],
      dtype=[('single_int', '<i8'), ('two_floats', '<f8', (2,))])

edit

Сохранение массива dtype объекта обходит множество проблем с форматированием:

In [182]: my_var                                                                                       
Out[182]: 
array([(1, [2., 3.]), (4, [5., 6.])],
      dtype=[('single_int', '<i8'), ('two_floats', '<f8', (2,))])
In [183]: def my_repr(o): 
     ...:             return [(elem['single_int'], *elem['two_floats']) for elem in o] 
     ...:                                                                                              
In [184]: my_repr(my_var)                                                                              
Out[184]: [(1, 2.0, 3.0), (4, 5.0, 6.0)]
In [185]: np.array(_,object)                                                                           
Out[185]: 
array([[1, 2.0, 3.0],
       [4, 5.0, 6.0]], dtype=object)
In [186]: np.savetxt('f.txt', _, fmt='%d %f %f')                                                       
In [187]: cat f.txt                                                                                    
1 2.000000 3.000000
4 5.000000 6.000000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...