Python dict to numpy структурированный массив
У меня есть словарь, который мне нужно преобразовать в структурированный массив NumPy. Я использую функцию arcpy NumPyArraytoTable
, поэтому структурированный массив NumPy - единственный формат данных, который будет работать.
Основано на этой теме: Запись в массив numpy из словаря и в эту тему: Как преобразовать объект словаря Python в массив numpy
Я пробовал это:
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
names = ['id','data']
formats = ['f8','f8']
dtype = dict(names = names, formats=formats)
array=numpy.array([[key,val] for (key,val) in result.iteritems()],dtype)
Но я продолжаю получать expected a readable buffer object
Метод ниже работает, но глуп и явно не будет работать для реальных данных. Я знаю, что есть более изящный подход, я просто не могу понять это.
totable = numpy.array([[key,val] for (key,val) in result.iteritems()])
array=numpy.array([(totable[0,0],totable[0,1]),(totable[1,0],totable[1,1])],dtype)
Ответы
Ответ 1
Вы можете использовать np.array(list(result.items()), dtype=dtype)
:
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
names = ['id','data']
formats = ['f8','f8']
dtype = dict(names = names, formats=formats)
array = np.array(list(result.items()), dtype=dtype)
print(repr(array))
дает
array([(0.0, 1.1181753789488595), (1.0, 0.5566080288678394),
(2.0, 0.4718269778030734), (3.0, 0.48716683119447185), (4.0, 1.0),
(5.0, 0.1395076201641266), (6.0, 0.20941558441558442)],
dtype=[('id', '<f8'), ('data', '<f8')])
Если вы не хотите создавать промежуточный список кортежей, list(result.items())
, то вместо этого вы можете использовать np.fromiter
:
В Python2:
array = np.fromiter(result.iteritems(), dtype=dtype, count=len(result))
В Python3:
array = np.fromiter(result.items(), dtype=dtype, count=len(result))
Почему использование списка [key,val]
не работает:
Кстати, ваша попытка,
numpy.array([[key,val] for (key,val) in result.iteritems()],dtype)
был очень близок к работе. Если вы измените список [key, val]
на кортеж (key, val)
, то это сработало бы. Конечно,
numpy.array([(key,val) for (key,val) in result.iteritems()], dtype)
это то же самое, что и
numpy.array(result.items(), dtype)
в Python2 или
numpy.array(list(result.items()), dtype)
в Python3.
np.array
обрабатывает списки не так, как кортежи: Роберт Керн объясняет:
Как правило, кортежи считаются "скалярными" записями, а списки повторяется Это правило помогает numpy.array() выяснить, какие последовательности являются записями и которые являются другими последовательностями, которые должны быть рекурсивны на; то есть, какие последовательности создают другое измерение, а какие являются атомные элементы.
Поскольку (0.0, 1.1181753789488595)
считается одним из этих атомарных элементов, он должен быть кортежем, а не списком.
Ответ 2
Еще проще, если вы используете pandas:
import pandas
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
df = pandas.DataFrame(result, index=[0])
print df
дает:
0 1 2 3 4 5 6
0 1.118175 0.556608 0.471827 0.487167 1 0.139508 0.209416
Ответ 3
Позвольте мне предложить улучшенный метод, когда значения словаря являются списками с одинаковой длиной:
import numpy
def dctToNdarray (dd, szFormat = 'f8'):
'''
Convert a 'rectangular' dictionnary to numpy NdArray
entry
dd : dictionnary (same len of list
retrun
data : numpy NdArray
'''
names = dd.keys()
firstKey = dd.keys()[0]
formats = [szFormat]*len(names)
dtype = dict(names = names, formats=formats)
values = [tuple(dd[k][0] for k in dd.keys())]
data = numpy.array(values, dtype=dtype)
for i in range(1,len(dd[firstKey])) :
values = [tuple(dd[k][i] for k in dd.keys())]
data_tmp = numpy.array(values, dtype=dtype)
data = numpy.concatenate((data,data_tmp))
return data
dd = {'a':[1,2.05,25.48],'b':[2,1.07,9],'c':[3,3.01,6.14]}
data = dctToNdarray(dd)
print data.dtype.names
print data
Ответ 4
Я бы предпочел хранить ключи и значения на отдельных массивах. Это я часто более практичен. Структуры массивов являются идеальной заменой массиву структур. Поскольку большую часть времени вам приходится обрабатывать только подмножество ваших данных (в этом случае ключи или значения, работа только с одним из двух массивов будет более эффективной, чем работа с половиной из двух массивов вместе.
Но если этот способ невозможен, я бы предложил использовать массивы, отсортированные по столбцу, а не по строке. Таким образом, вы будете иметь такую же выгоду, как наличие двух массивов, но упакованных только в одном.
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
names = 0
values = 1
array = np.empty(shape=(2, len(result)), dtype=float)
array[names] = r.keys()
array[values] = r.values()
Но мой любимый это (проще):
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
arrays = {'names': np.array(k.keys(), dtype=float),
'values': np.array(k.values(), dtype=float)}
Ответ 5
Аналогично утвержденному ответу. Если вы хотите создать массив из ключей словаря:
np.array( tuple(dict.keys()) )
Если вы хотите создать массив из значений словаря:
np.array( tuple(dict.values()) )