Как создать numpy.ndarray из итерации кортежа

#python #numpy #multidimensional-array

#python #numpy #многомерный массив

Вопрос:

У меня есть следующий цикл

 # `results` are obtained from some mySQldb command.

for row in results:
    print row
  

Который печатает кортежи следующим образом:

 ('1A34', 'RBP', 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
('1A9N', 'RBP', 0.0456267, 0.0539268, 0.331932, 0.0464031, 4.41336e-06, 0.522107)
('1AQ3', 'RBP', 0.0444479, 0.201112, 0.268581, 0.0049757, 1.28505e-12, 0.480883)
('1AQ4', 'RBP', 0.0177232, 0.363746, 0.308995, 0.00169861, 0.0, 0.307837)
  

Мой вопрос из этой итерации, как я могу создать неровный nd.array, который выглядит следующим образом:

 array([['1A34', 'RBP', 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
       ['1A9N', 'RBP', 0.0456267, 0.0539268, 0.331932, 0.0464031, 4.41336e-06, 0.522107],
       ['1AQ3', 'RBP', 0.0444479, 0.201112, 0.268581, 0.0049757, 1.28505e-12, 0.480883],
       ['1AQ4', 'RBP', 0.0177232, 0.363746, 0.308995, 0.00169861, 0.0, 0.307837]])
  

В конце ndarray будет иметь форму: (4,8)

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

1. Вам нужно иметь str и float в одном array ? Это можно сделать, structured array но это не идеальное решение. Обычный массив допускает только один тип ( dtype как известно). Рассматриваете возможность использования pandas ?

2. Если results это генератор, вам нужно сначала преобразовать его в список. Причина в том, что массивы numpy должны знать их размер во время создания. Если вы знаете количество элементов в results , то вы можете сделать что-то вроде a = numpy.empty((n, 8), dtype='object') , за которым следует: for i, row in enumerate(results): a[i] = row .

3. @AlokSinghal, не совсем верно, есть numpy.fromiter функция.

4. @CTZhu спасибо, что упомянули об этом. Хотя кажется fromiter , что перераспределяет массив для каждого нового элемента, если count не указано иное. Редактировать : просто посмотрел на исходный код, и, похоже, он увеличивается на 50% при каждом новом распределении, так что это может быть не так плохо, как я думал.

Ответ №1:

Считайте его в структурированный массив:

 In [30]:
a=[('1A34', 'RBP', 0.0, 1.0, 0.0, 0.0, 0.0, 0.0),
   ('1A9N', 'RBP', 0.0456267, 0.0539268, 0.331932, 0.0464031, 4.41336e-06, 0.522107),
   ('1AQ3', 'RBP', 0.0444479, 0.201112, 0.268581, 0.0049757, 1.28505e-12, 0.480883),
   ('1AQ4', 'RBP', 0.0177232, 0.363746, 0.308995, 0.00169861, 0.0, 0.307837)]
np.array(a, dtype=('a10,a10,f4,f4,f4,f4,f4,f4'))
Out[30]:
array([('1A34', 'RBP', 0.0, 1.0, 0.0, 0.0, 0.0, 0.0),
       ('1A9N', 'RBP', 0.045626699924468994, 0.053926799446344376, 0.331932008266449, 0.04640309885144234, 4.413359874888556e-06, 0.5221070051193237),
       ('1AQ3', 'RBP', 0.044447898864746094, 0.20111200213432312, 0.26858100295066833, 0.004975699819624424, 1.2850499744171406e-12, 0.48088300228118896),
       ('1AQ4', 'RBP', 0.01772320084273815, 0.3637459874153137, 0.30899500846862793, 0.0016986100235953927, 0.0, 0.30783700942993164)], 
      dtype=[('f0', 'S10'), ('f1', 'S10'), ('f2', '<f4'), ('f3', '<f4'), ('f4', '<f4'), ('f5', '<f4'), ('f6', '<f4'), ('f7', '<f4')])
  

Вы можете иметь их все в object dtype :

 In [46]:

np.array(a, dtype=object)
Out[46]:
array([['1A34', 'RBP', 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
       ['1A9N', 'RBP', 0.0456267, 0.0539268, 0.331932, 0.0464031,
        4.41336e-06, 0.522107],
       ['1AQ3', 'RBP', 0.0444479, 0.201112, 0.268581, 0.0049757,
        1.28505e-12, 0.480883],
       ['1AQ4', 'RBP', 0.0177232, 0.363746, 0.308995, 0.00169861, 0.0,
        0.307837]], dtype=object)
  

но это не идеально для float значений, также это может привести к нежелательному поведению:

 In [48]:
b=np.array(a, dtype=object)
b[0] b[1] #addition for float values and concatenation for string values
Out[48]:
array(['1A341A9N', 'RBPRBP', 0.0456267, 1.0539268, 0.331932, 0.0464031,
       4.41336e-06, 0.522107], dtype=object)
  

pandas также является альтернативой:

 In [43]:
import pandas as pd
print pd.DataFrame(a)
      0    1         2         3         4         5             6         7
0  1A34  RBP  0.000000  1.000000  0.000000  0.000000  0.000000e 00  0.000000
1  1A9N  RBP  0.045627  0.053927  0.331932  0.046403  4.413360e-06  0.522107
2  1AQ3  RBP  0.044448  0.201112  0.268581  0.004976  1.285050e-12  0.480883
3  1AQ4  RBP  0.017723  0.363746  0.308995  0.001699  0.000000e 00  0.307837
In [44]:

pd.DataFrame(a).dtypes
Out[44]:
0     object
1     object
2    float64
3    float64
4    float64
5    float64
6    float64
7    float64
dtype: object
  

и это позволяет столбцам иметь разные dtype

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

1. Спасибо за предложение panda. Но мне нужен numpy, как того требует scikit-learn.

2.Добро пожаловать, в этом случае я буду рекомендовать кодировать строковые значения для фиктивных переменных или факторов (0, 1, 2, 3… ), таким образом, каждая вещь может быть помещена в обычную numpy array float dtype

3. это undesired behaviour исключительно для object типа данных? Если я жестко закодирую, используя ваше предложение dtype=[('f0', 'S10'), ('f1', 'S10'), ('f2', '<f4'), ('f3', '<f4'), ('f4', '<f4'), ('f5', '<f4'), ('f6', '<f4'), ('f7', '<f4')]) , этот побочный эффект не должен возникать, верно?

4. Кстати, форма (4,) не (4,8) является . Как я могу сделать это правильно, чтобы получить последнюю форму?

5. Да, как только у вас есть данные в a structured array , форма становится (4,) . 8 исчез (и вместо этого у вас теперь есть 8 поля, f0 to f7 ).