2016-08-30 4 views
0

У меня есть текстовый файл, который выглядит следующим образом:Python Импорт текст Массив Numpy

... 
5 [0, 1] [512, 479] 991 
10 [1, 0] [706, 280] 986 
15 [1, 0] [807, 175] 982 
20 [1, 0] [895, 92] 987 
... 

Каждый столбец вкладка разделена, но есть массивы в некоторых из столбцов. Могу ли я импортировать их с np.genfromtxt в некотором роде?

Полученные распакованные списки должны быть, например:

data1 = [..., 5, 10, 15, 20, ...] 
data2 = [..., [512, 479], [706, 280], ... ] (i.e. a 2D list) 
etc. 

Я попытался

data1, data2, data3, data4 = np.genfromtxt('data.txt', dtype=None, delimiter='\t', unpack=True)

но data2 и data3 списки, содержащие 'нан'.

+0

Если genfromttxt не работает, попробуйте что-то еще, например, итерацию по строкам и построение списков, которые можно использовать numpy для создания массива. – wwii

+0

Возможно, вы можете использовать параметры '' 'usecols'' и' '' преобразователи'' genfromtxt – wwii

+1

Скобки облегчают использование запасных txt-загрузчиков. Пробовали ли вы читать файл по строкам и самостоятельно разбирали каждую строку? – hpaulj

ответ

0

Кронштейны в файле csv являются klunky независимо от того, как вы на это смотрите. Структура по умолчанию csv представляет собой 2d - строки и равномерные столбцы. Скобки добавляют уровень гнездования. Но тот факт, что столбцы разделены на вкладку, а вложенные блоки разделены запятой, делает это немного проще.

Ваш комментарий код (с добавлением новых строк)

datastr = data[i][1][1:-1].split(',') 
dataarray = [] 
for j in range(0, len(datastr)): 
    dataarray.append(int(datastr[j])) 
data2.append(dataarray) 

Я предполагаю, что data[i] выглядит примерно так (после закладки раскола):

['5', '[0, 1]', '[512, 479]', '991'] 

Таким образом, для '[0,1] вы полосу [], разделите остальные и верните этот список на data2.

Это, безусловно, похоже на жизнеспособный подход. genfromtxt обрабатывает скобки или кавычки. Читатель csv может обрабатывать цитируемый текст и может быть адаптирован для обработки [] в виде цитат. Но кроме этого, я думаю, что «[]` нужно обрабатывать с какой-то строковой обработкой, как и вы.

Имейте в виду, что genfromtxt просто считывает строки, анализирует их и собирает результирующие списки в главном списке. Затем он преобразует этот список в массив в конце. Поэтому, делая свою собственную строку за строкой, строка с помощью строкового разбора не уступает.

=============

С вашего образца в виде текстового файла:

In [173]: txt=b""" 
...: 5 \t [0, 1] \t [512, 479] \t 991 
...: 10 \t [1, 0] \t [706, 280] \t 986 
...: 15 \t [1, 0] \t [807, 175] \t 982 
...: 20 \t [1, 0] \t [895, 92] \t 987""" 

Простой genfromtxt вызов с dtype=None:

In [186]: data = np.genfromtxt(txt.splitlines(), dtype=None, delimiter='\t', autostrip=True) 

Результатом является структурированный массив с целыми и строковыми полями:

In [187]: data 
Out[187]: 
array([(5, b'[0, 1]', b'[512, 479]', 991), 
     (10, b'[1, 0]', b'[706, 280]', 986), 
     (15, b'[1, 0]', b'[807, 175]', 982), 
     (20, b'[1, 0]', b'[895, 92]', 987)], 
     dtype=[('f0', '<i4'), ('f1', 'S6'), ('f2', 'S10'), ('f3', '<i4')]) 

Поля доступны по имени

In [188]: data['f0'] 
Out[188]: array([ 5, 10, 15, 20]) 
In [189]: data['f1'] 
Out[189]: 
array([b'[0, 1]', b'[1, 0]', b'[1, 0]', b'[1, 0]'], 
     dtype='|S6') 

Если мы можем иметь дело с [], ваши данные могут быть хорошо представляли собой структурированный массив с соединением DTYPE

In [191]: dt=np.dtype('i,2i,2i,i') 
In [192]: np.ones((3,),dtype=dt) 
Out[192]: 
array([(1, [1, 1], [1, 1], 1), (1, [1, 1], [1, 1], 1), 
     (1, [1, 1], [1, 1], 1)], 
     dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')]) 

где поле «f1» является a (3,2).

Один из подходов - передать текст/файл через функцию, которая отфильтровывает лишние символы. genfromtxt работает со всем, что будет кормить его по очереди.

def afilter(txt): 
    for line in txt.splitlines(): 
     line=line.replace(b'[', b' ').replace(b']', b'').replace(b',' ,b'\t') 
     yield line 

Этот генератор удаляет [] и заменяет, с вкладкой, в действительности производит плоский файл CSV

In [205]: list(afilter(txt)) 
Out[205]: 
[b'', 
b'5 \t 0\t 1 \t 512\t 479 \t 991', 
b'10 \t 1\t 0 \t 706\t 280 \t 986', 
b'15 \t 1\t 0 \t 807\t 175 \t 982', 
b'20 \t 1\t 0 \t 895\t 92 \t 987'] 

genfromtxt с dtype=None будет производить массив с 6 столбцов.

In [209]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=None) 
In [210]: data 
Out[210]: 
array([[ 5, 0, 1, 512, 479, 991], 
     [ 10, 1, 0, 706, 280, 986], 
     [ 15, 1, 0, 807, 175, 982], 
     [ 20, 1, 0, 895, 92, 987]]) 
In [211]: data.shape 
Out[211]: (4, 6) 

Но если я дам ему dt DTYPE я определил выше, я получаю структурированный массив:

In [206]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=dt) 
In [207]: data 
Out[207]: 
array([(5, [0, 1], [512, 479], 991), (10, [1, 0], [706, 280], 986), 
     (15, [1, 0], [807, 175], 982), (20, [1, 0], [895, 92], 987)], 
     dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')]) 
In [208]: data['f1'] 
Out[208]: 
array([[0, 1], 
     [1, 0], 
     [1, 0], 
     [1, 0]], dtype=int32) 

Скобки может рассматриваться на нескольких уровнях. Я не думаю, что есть много преимуществ одного над другим.

1

Потенциальный подход для приведенных данных, однако, не используя NumPy:

import ast 

data1, data2, data3, data4 = [],[],[],[] 

for l in open('data.txt'): 
    data = l.split('\t') 

    data1.append(int(data[0])) 
    data2.append(ast.literal_eval(data[1])) 
    data3.append(ast.literal_eval(data[2])) 
    data4.append(int(data[3])) 

print 'data1', data1 
print 'data2', data2 
print 'data3', data3 
print 'data4', data4 

дает

"data1 [5, 10, 15, 20]" 
"data2 [[0, 1], [1, 0], [1, 0], [1, 0]]" 
"data3 [[512, 479], [706, 280], [807, 175], [895, 92]]" 
"data4 [991, 986, 982, 987]" 
+0

Эти списки 'datan' могут быть легко превращены в массивы в конце. Таким образом, нет никакой потери скорости или функциональности для этого. – hpaulj

+0

@hpaulj Это хороший момент! – LukeBowl

0

В качестве альтернативы genfromtxt вы можете попробовать fromregex. В основном вы создаете аналогию между группами регулярных выражений и полями типа numpy structured dtype.

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

import numpy as np 

# regular expression that will extract 6 numbers from each line 
re = 6 * r"(\d+)\D*" 

# dtype for a single number 
dt_num = np.int 

# structured dtype of 6 numbers 
dt = 6 * [('', dt_num)] 

# parse the file 
a = np.fromregex("data.txt", re, dt) 

# change to a more descriptive structured dtype 
a.dtype = [ 
    ('data1', dt_num), 
    ('data2', dt_num, (2,)), 
    ('data3', dt_num, (2,)), 
    ('data4', dt_num) 
] 

print(a['data1']) 
print(a['data2']) 
print(a['data3']) 
print(a['data4']) 

Хорошая вещь о переключении DTYPE в виде Numpy массива является то, что он не должен обрабатывать или создавать новые копии данных, это просто переосмысливает то, что вы получаете, когда вы получаете доступ к данным.

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

Смежные вопросы