нарезать массив с символами - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть текстовый файл, сделанный как:

0.01 1 0.1 1 10 100 a
0.02 3 0.2 2 20 200 b
0.03 2 0.3 3 30 300 c
0.04 1 0.4 4 40 400 d

Я читаю его как список A, а затем преобразую в массив Numpy, то есть:

>>> A
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b'],
       ['0.03', '2', '0.3', '3', '30', '300', 'c'],
       ['0.04', '1', '0.4', '4', '40', '400', 'd']], 
      dtype='|S4')

Я просто хочу извлечь подмассив B, сделанный из A, где его 4-я запись меньше 30, что должно выглядеть примерно так:

B = array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
           ['0.02', '3', '0.2', '2', '20', '200', 'b']])

При работе с массивами я обычно делаю просто B = A[A[:,4]<30], но в этом случае (возможно, из-за присутствия символов / строк, с которыми я никогда не работал) это не работает, давая мне следующее:

>>> A[A[:,4]<30]
array(['0.01', '1', '0.1', '1', '10', '100', 'a'], 
      dtype='|S4')

и я не могу понять причину. Я не имею дело с моим кодом, и я не думаю, что смогу переключить все это на структуры или словари: какие-либо предложения для этого с массивами numpy? Заранее большое спасибо!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018
In [86]: txt='''0.01 1 0.1 1 10 100 a
    ...: 0.02 3 0.2 2 20 200 b
    ...: 0.03 2 0.3 3 30 300 c
    ...: 0.04 1 0.4 4 40 400 d'''
In [87]: A = np.genfromtxt(txt.splitlines(), dtype=str)
In [88]: A
Out[88]: 
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b'],
       ['0.03', '2', '0.3', '3', '30', '300', 'c'],
       ['0.04', '1', '0.4', '4', '40', '400', 'd']], dtype='<U4')
In [89]: A[:,4]
Out[89]: array(['10', '20', '30', '40'], dtype='<U4')

genfromtxt, по умолчанию пытается сделать поплавки. Но в этом случае символьный столбец будет nan. Вместо этого я указал str dtype.

Таким образом, числовой тест потребует преобразования столбца в числа:

In [90]: A[:,4].astype(int)
Out[90]: array([10, 20, 30, 40])
In [91]: A[:,4].astype(int)<30
Out[91]: array([ True,  True, False, False])

В этом случае также работает сравнение строк:

In [99]: A[:,4]<'30'
Out[99]: array([ True,  True, False, False])

Или, если мы используем dtype = None, он выводит dtype по столбцу и создает структурированный массив:

In [93]: A1 = np.genfromtxt(txt.splitlines(), dtype=None,encoding=None)
In [94]: A1
Out[94]: 
array([(0.01, 1, 0.1, 1, 10, 100, 'a'), (0.02, 3, 0.2, 2, 20, 200, 'b'),
       (0.03, 2, 0.3, 3, 30, 300, 'c'), (0.04, 1, 0.4, 4, 40, 400, 'd')],
      dtype=[('f0', '<f8'), ('f1', '<i8'), ('f2', '<f8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8'), ('f6', '<U1')])

Теперь мы можем выбрать поле по имени и проверить его:

In [95]: A1['f4']
Out[95]: array([10, 20, 30, 40])

В любом случае мы можем выбирать строки на основе маски True / False или соответствующих индексов строк:

In [96]: A[[0,1],:]
Out[96]: 
array([['0.01', '1', '0.1', '1', '10', '100', 'a'],
       ['0.02', '3', '0.2', '2', '20', '200', 'b']], dtype='<U4')

In [98]: A1[[0,1]]     # A1 is 1d
Out[98]: 
array([(0.01, 1, 0.1, 1, 10, 100, 'a'), (0.02, 3, 0.2, 2, 20, 200, 'b')],
      dtype=[('f0', '<f8'), ('f1', '<i8'), ('f2', '<f8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8'), ('f6', '<U1')])
0 голосов
/ 29 апреля 2018

Вы должны сравнить int с int

A[A[:,4].astype(int)<30]

или str до str

A[A[:,4]<'30'] 

Однако обратите внимание, что последний будет работать в вашем конкретном примере , но не будет работать вообще, потому что вы сравниваете str упорядочение (например, '110' < '30' возвращает True, но 110 < 30 возвращает False)


numpy выведет типы ваших элементов из ваших данных. В этом случае он приписывает type = '|S4' вашим элементам, что означает, что они представляют собой строки длиной 4. Это, вероятно, является следствием базового кода C (который повышает производительность numpy), который требует, чтобы элементы имели фиксированные типы ,

Чтобы проиллюстрировать эту разницу, проверьте следующий код:

>>> np.array([['0.01', '1', '0.1', '1', '10', '100', 'a']])
array(['0.01', '1', '0.1', '1', '10', '100', 'a'], dtype='|S4')

Предполагаемый тип строк длиной 4, которая является максимальной длиной ваших элементов (в элементе 0.01). Теперь, если вы явно определите его для хранения объектов общего типа, он будет делать то, что вы хотите

>>> np.array([[0.01, 1, 0.1, 1, 10, 100, 'a']], dtype=object)
array([0.01, 1, 0.1, 1, 10, 100, 'a'], dtype=object)

и ваш код A[A[:,4]<30] будет работать правильно.

Для получения дополнительной информации это является очень полным руководством

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...