Применять строковые операции к пустым массивам?

Есть ли лучшие способы применить строковые операции к ndarrayа не перебирать их? Я хотел бы использовать "векторизованную" операцию, но я могу думать только об использовании map (пример показан) или список пониманий.

Arr = numpy.rec.fromrecords(zip(range(5),'as far as i know'.split()),
                            names='name, strings')

print ''.join(map(lambda x: x[0].upper()+'.',Arr['strings']))
=> A.F.A.I.K.

Например, в языке R строковые операции также векторизованы:

> (string <- unlist(strsplit("as far as i know"," ")))
[1] "as"   "far"  "as"   "i"    "know"
> paste(sprintf("%s.",toupper(substr(string,1,1))),collapse="")
[1] "A.F.A.I.K."

2 ответа

Решение

Обновление: См . Ответ Ларсмана на этот вопрос: Нампи недавно добавил numpy.char модуль для базовых строковых операций.

Краткий ответ: Numpy не предоставляет векторизованные строковые операции. Идиоматический способ сделать что-то вроде (где Arr это ваш массив NumPy):

print '.'.join(item.upper() for item in Arr['strings'])

Длинный ответ, вот почему numpy не предоставляет векторизованные строковые операции: (и между ними много хорошего)

Один размер не подходит всем, когда речь идет о структурах данных.

Ваш вопрос, вероятно, кажется странным для людей, пришедших с языка, не зависящего от предметной области, но он имеет большой смысл для людей, пришедших с языка, специфичного для предметной области.

Python предоставляет вам широкий выбор структур данных. Некоторые структуры данных лучше в некоторых задачах, чем другие.

Во-первых, массивы numpy не являются контейнером "hold-all" по умолчанию в python. Встроенные контейнеры Python очень хороши для того, для чего они предназначены. Часто список или диктат - это то, что вы хотите.

Numpy - х ndarray s для однородных данных.

Короче говоря, у numpy нет векторизованных строковых операций.

ndarray Это специализированный контейнер, предназначенный для хранения N-мерных однородных групп элементов в минимально возможном объеме памяти. Акцент действительно делается на минимизации использования памяти (я пристрастен, потому что это в основном то, что мне нужно, но это полезный способ думать об этом.). Векторизованные математические операции - это просто приятный побочный эффект хранения вещей в непрерывном блоке памяти.

Струны обычно бывают разной длины.

Например ['Dog', 'Cat', 'Horse'], Numpy использует похожий на базу данных подход, требующий от вас определения длины для ваших строк, но тот простой факт, что строки не должны быть фиксированной длины, имеет много последствий.

Наиболее полезные строковые операции возвращают строки переменной длины. (например '.'.join(...) в твоем примере)

Те, которые не (например, верхний и т. Д.), Вы можете имитировать с другими операциями, если хотите. (Например, верхний примерно (x.view(np.uint8) - 32).view('S1'), Я не рекомендую вам это делать, но вы можете...)

В качестве основного примера: 'A' + 'B' доходность 'AB', 'AB' не такой же длины, как 'A' или же 'B', Numpy имеет дело с другими вещами, которые делают это (например, np.uint8(4) + np.float(3.4)), но строки гораздо гибче по длине, чем числа. (Правила "Upcasting" и "downcasting" для чисел довольно просты.)

Еще одна причина, по которой numpy этого не делает, заключается в том, что основное внимание уделяется численным операциям. 'A'**2 не имеет конкретного определения в Python (Вы, конечно, можете создать строковый класс, но каким он должен быть?). Строковые массивы являются гражданами второго сорта в NumPy. Они существуют, но большинство операций для них не определены.

Python уже действительно хорош в обработке строк

Другая (и действительно главная) причина, по которой numpy не пытается предлагать строковые операции, заключается в том, что python уже действительно хорош в этом.

Списки - это фантастические гибкие контейнеры. Python имеет огромный набор очень хороших, очень быстрых строковых операций. Постижения списков и выражения генераторов довольно быстрые, и они не испытывают лишних усилий, пытаясь угадать, каким должен быть тип или размер возвращаемого элемента, так как им все равно. (Они просто хранят указатель на него.)

Кроме того, итерация по пустым массивам в python медленнее, чем итерация по списку или кортежу в python, но для строковых операций вам действительно лучше всего использовать обычные выражения списка / генератора. (например print '.'.join(item.upper() for item in Arr['strings']) в вашем примере) Еще лучше, не используйте пустые массивы для хранения строк. Это имеет смысл, если у вас есть один столбец структурированного массива со строками, но это все. Python предоставляет вам очень богатые и гибкие структуры данных. Массив Numpy - это не конец и не конец, а специализированный случай, а не обобщенный случай.

Кроме того, имейте в виду, что большинство из того, что вы хотели бы сделать с массивом numpy

Учите Python, а не только Numpy

Я не пытаюсь быть дерзким, но работа с массивами-пустышками очень похожа на многие вещи в Matlab, R или IDL и т. Д.

Это знакомая парадигма, и любой первый инстинкт должен попытаться применить ту же самую парадигму к остальной части языка.

Python намного больше, чем просто тупица. Это мультипарадигмальный язык, поэтому легко придерживаться тех парадигм, к которым вы уже привыкли. Попробуйте научиться "думать в питоне", а также просто "думать в ноль". Numpy предоставляет определенную парадигму для python, но там гораздо больше, и некоторые парадигмы лучше подходят для некоторых задач, чем другие.

Отчасти это становится знакомством с сильными и слабыми сторонами различных контейнеров данных (списки против dicts против кортежей и т. Д.), А также с различными парадигмами программирования (например, объектно-ориентированный или функциональный, процедурный и т. Д.).

В целом, Python имеет несколько различных типов специализированных структур данных. Это несколько отличает его от предметно-ориентированных языков, таких как R или Matlab, которые имеют несколько типов структур данных, но сосредоточены на выполнении всего с одной конкретной структурой. (Мой опыт работы с R ограничен, поэтому я могу ошибаться, но в любом случае это мое впечатление об этом. Во всяком случае, это верно и в отношении Matlab.)

Во всяком случае, я не пытаюсь разглагольствовать здесь, но мне потребовалось довольно много времени, чтобы перестать писать Фортран в Matlab, и мне потребовалось еще больше времени, чтобы перестать писать Matlab на python. Этот бессвязный ответ очень похож на конкретные примеры, но, надеюсь, он имеет хоть какой-то смысл и немного помогает.

Да, недавно NumPy векторизовал строковые операции в numpy.char модуль. Например, когда вы хотите найти все строки, начинающиеся с B, в массиве строк, это

>>> y = np.asarray("B-PER O O B-LOC I-LOC O B-ORG".split())
>>> y
array(['B-PER', 'O', 'O', 'B-LOC', 'I-LOC', 'O', 'B-ORG'], 
      dtype='|S5')
>>> np.char.startswith(y, 'B')
array([ True, False, False,  True, False, False,  True], dtype=bool)
Другие вопросы по тегам