Применить строковое преобразование к 2d-массиву по определенной оси, векторизованной

#python #python-3.x #numpy

#python #python-3.x #numpy

Вопрос:

Учитывая следующий ndarray:

 toy_array = np.array([["12He", "ds", "jgjd", "22id", "d32311"],
                      ["g76g", "dfq", "qqz", "mng2", "232gh7"],
                      ["h765", "sds", "232", "7654", "233vcz"]])
print(toy_array)
array([['12He', 'ds', 'jgjd', '22id', 'd32311'],
       ['g76g', 'dfq', 'qqz', 'mng2', '232gh7'],
       ['h765', 'sds', '232', '7654', '233vcz']], dtype='<U6')
 

(3, 5) мне нужно, чтобы для каждой строки получить строковое представление массива.
Я могу сделать это, повторив toy_array , выполнив:

 str_transform_f = lambda arr: str(arr)
np.apply_along_axis(func1d=str_transform_f, axis=1, arr=toy_array)

array(["['12He' 'ds' 'jgjd' '22id' 'd32311']",
       "['g76g' 'dfq' 'qqz' 'mng2' '232gh7']",
       "['h765' 'sds' '232' '7654' '233vcz']"], dtype='<U36')
 

Что также является ожидаемым результатом. Однако на самом деле toy_array размеры находятся в величине (10000, 1000) , что делает этот метод медленным.

Я пытался найти решение, используя множество строковых операций numpy, например. array2string, но не могу понять, как применить его к определенной оси векторизованным способом.

Есть идеи?

Комментарии:

1. Вы пробовали панд?

2. Если numpy метод не предоставляет параметр оси, это не поможет. Я не видел никакой необходимости в такого рода выводе. Почему бы не применить splitlines ко str всему массиву?

3. Форматирование списка происходит быстрее: [str(row) for row in arr.tolist()]

Ответ №1:

Вы получите лучшую производительность при понимании списка следующим образом:

 np.array([str(row) for row in toy_array])
 

Для меня это работает чуть более чем в 2 раза быстрее, чем ваша первоначальная попытка:

 import timeit
timeit.timeit(
  stmt='''str_transform_f = lambda arr: str(arr)
          np.apply_along_axis(func1d=str_transform_f, axis=1, arr=toy_array)''',
  setup='''import numpy as np;
           toy_array = np.array([["12He", "ds", "jgjd", "22id", "d32311"],
                      ["g76g", "dfq", "qqz", "mng2", "232gh7"],
                      ["h765", "sds", "232", "7654", "233vcz"]])''',
  number=10000)

1.2746390000002066
 

Сравните это с этим:

 import timeit
timeit.timeit(
    stmt='np.array([str(row) for row in toy_array])',
    setup='''import numpy as np;
             toy_array = np.array([["12He", "ds", "jgjd", "22id", "d32311"],
                      ["g76g", "dfq", "qqz", "mng2", "232gh7"],
                      ["h765", "sds", "232", "7654", "233vcz"]])''',
    number=10000)

0.6134616999997888
 

Комментарии:

1. Спасибо за ваше предложение. Это заметно быстрее, хотя все еще итерация, чего я надеюсь избежать. Однако, если это невозможно, я воспользуюсь вашим решением.

2. Да, apply_along... это может быть удобно с массивами более высокой размерности, но это не быстрый инструмент. И пропустите np.array оболочку при понимании, если результат списка так же хорош.