Numpy unique изменяет целое число на строку

#python #numpy #unique

#python #numpy #уникальный

Вопрос:

У меня есть таблица данных, в которой есть столбцы string и integer, такие как:

 test_data = [('A',1,2,3),('B',4,5,6),('A',1,2,3)]
  

Мне нужны уникальные строки, поэтому я использовал уникальную функцию numpy:

 summary, repeat = np.unique(test_data,return_counts=True, axis=0)
  

Но после этого мои типы данных меняются. Итог таков:

 array([['A', '1', '2', '3'],
   ['B', '4', '5', '6']], dtype='<U1')
  

Все типы данных теперь являются строковыми. Как я могу предотвратить это изменение? (Python 3.7, numpy 1.16.4)

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

1. Вы не можете хранить несколько разных типов данных в массиве. но поскольку все они могут быть символами, python автоматически примет значение char и преобразует их. Если бы вы сохранили их отдельно, вы получили бы целочисленный массив из целых чисел.

2. @jaSnom не совсем «символ», но да, в значительной степени

3. @juanpa.arrivillaga да, вы правы. работа с Java и python на моей работе иногда заставляет меня их смешивать.

4. @juanpa.arrivillaga. технически у вас может быть recarray или массив объектов с кортежами

5. @MadPhysicist конечно, но технически они все еще хранят однородный тип данных, структурированный dtype или object 🙂

Ответ №1:

Если у вас есть объекты Python и вы хотите сохранить их как объекты python, используйте функции python:

 unique_rows = set(test_data)
  

Или еще лучше:

 from collections import Counter

rows_and_counts = Counter(test_data)
  

Эти решения не копируют данные: они сохраняют ссылки на исходные кортежи такими, какие они есть. Решение numpy копирует данные несколько раз: один раз при преобразовании в numpy, по крайней мере, один раз при сортировке и, возможно, больше при обратном преобразовании.

Эти решения имеют O(N) алгоритмическую сложность, потому что они оба используют хэш-таблицу. unique Решение numpy использует сортировку и поэтому имеет O(N log N) сложность.

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

1. Основываясь на вашем ответе, я хочу получить список ключей и значений отдельно, например: подсчитано = Счетчик (test_data) сводка, повтор = список (подсчитано.ключи ()), список(подсчитано.значения()). Есть ли какая-либо возможность, что последовательности списков могут отличаться.

2. @kurag. Нет. Ключи и значения словаря всегда возвращаются в одном и том же порядке. Это часть контракта. Счетчик является подклассом dictionary. Если вы действительно беспокоитесь, сделайте summary = list(counted); repeat = [counted[k] for k in summary]

Ответ №2:

Вы могли бы явно указать свой dtype в функции np.array, предшествующей np.unique:

 test_data = [('A',1,2,3),('B',4,5,6),('A',1,2,3)]

test_data = np.array(test_data, dtype=[('letter', '<U1'),
                                ('x', np.int),
                                 ('y', np.int),
                                 ('z', np.int)])
                                 
summary, repeat = np.unique(test_data,return_counts=True, axis=0)

  

Затем сводка выглядит следующим образом:

 array([('A', 1, 2, 3), ('B', 4, 5, 6)],
      dtype=[('letter', '<U1'), ('x', '<i4'), ('y', '<i4'), ('z', '<i4')])
  

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

1. Эти данные поступают из таблицы sql, поэтому мне нужно взять типы данных из таблицы sql и добавить к данным.

2. @kurag почему вы используете numpy здесь? В любом случае, я не уверен, что понимаю проблему с этим ответом, почему это имеет значение, если оно получено из таблицы SQL?

3. @wprazuch Данные взяты из sql и выполнены некоторые операции над ним, на одном этапе мне нужны уникальные строки с количеством повторений). Я могу использовать ваш ответ, но сначала контролирую исходные типы данных. Если я сделал это, я могу использовать также ответ Aratz с изменениями, но ваш ответ будет короче. Но я ищу ответ на numpy сам по себе, если он есть. И, как я уже сказал Арацу, это должно быть в numpy, numpy after operations должен представлять исходную структуру, а не отредактированную версию.

4. @kurag Если это так, то пока мне ничего не приходит в голову

5. @kurag. Вы понимаете, что np.unique на самом деле это не так эффективно? Набор Python или счетчик имеют лучшую производительность масштабирования

Ответ №3:

Я думаю, это связано с тем фактом, что в массиве numpy все элементы должны иметь один и тот же тип, вместо этого вы могли бы попытаться проанализировать ваш результат, когда он выйдет из numpy, например:

 result = []
for l in summary.tolist():
    new_l = []
    for v in l:
        try:
            new_l.append(int(v))
        except ValueError:
            new_l.append(v)
    result.append(tuple(new_l))
  

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

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