Создание dataframe из словаря, где записи имеют разную длину
Скажем, у меня есть словарь с 10 парами ключ-значение. Каждая запись содержит массив numpy. Однако длина массива не одинакова для всех из них.
Как создать фреймворк данных, где каждый столбец содержит другую запись?
Когда я пытаюсь:
pd.DataFrame(my_dict)
Я получаю:
ValueError: arrays must all be the same length
Любой способ преодолеть это? Я рад, что Pandas использовал NaN
для заполнения этих столбцов для более коротких записей.
Ответы
Ответ 1
В Python 3.x:
In [6]: d = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )
In [7]: DataFrame(dict([ (k,Series(v)) for k,v in d.items() ]))
Out[7]:
A B
0 1 1
1 2 2
2 NaN 3
3 NaN 4
В Python 2.x:
замените d.items()
на d.iteritems()
.
Ответ 2
Вот простой способ сделать это:
In[20]: my_dict = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )
In[21]: df = pd.DataFrame.from_dict(my_dict, orient='index')
In[22]: df
Out[22]:
0 1 2 3
A 1 2 NaN NaN
B 1 2 3 4
In[23]: df.transpose()
Out[23]:
A B
0 1 1
1 2 2
2 NaN 3
3 NaN 4
Ответ 3
Ниже приведен способ привести в порядок ваш синтаксис, но, в сущности, сделать то же самое, что и в других ответах:
>>> mydict = {'one': [1,2,3], 2: [4,5,6,7], 3: 8}
>>> dict_df = pd.DataFrame({ key:pd.Series(value) for key, value in mydict.items() })
>>> dict_df
one 2 3
0 1.0 4 8.0
1 2.0 5 NaN
2 3.0 6 NaN
3 NaN 7 NaN
Аналогичный синтаксис существует и для списков:
>>> mylist = [ [1,2,3], [4,5], 6 ]
>>> list_df = pd.DataFrame([ pd.Series(value) for value in mylist ])
>>> list_df
0 1 2
0 1.0 2.0 3.0
1 4.0 5.0 NaN
2 6.0 NaN NaN
Другой синтаксис для списков:
>>> mylist = [ [1,2,3], [4,5], 6 ]
>>> list_df = pd.DataFrame({ i:pd.Series(value) for i, value in enumerate(mylist) })
>>> list_df
0 1 2
0 1 4.0 6.0
1 2 5.0 NaN
2 3 NaN NaN
Во всех этих случаях вы должны быть осторожны, чтобы проверить, какой тип данных pandas
будет угадывать для ваших столбцов. Столбцы, содержащие любые (отсутствующие) значения NaN
, будут преобразованы, например, в число с плавающей точкой.
Ответ 4
Хотя это напрямую не отвечает на вопрос ОП. Я нашел это отличным решением для моего случая, когда у меня были неравные массивы, и я хотел бы поделиться:
из pandas документации
In [31]: d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
....: 'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
....:
In [32]: df = DataFrame(d)
In [33]: df
Out[33]:
one two
a 1 1
b 2 2
c 3 3
d NaN 4
Ответ 5
Вы также можете использовать pd.concat
по axis=1
со списком объектов pd.Series
:
import pandas as pd, numpy as np
d = {'A': np.array([1,2]), 'B': np.array([1,2,3,4])}
res = pd.concat([pd.Series(v, name=k) for k, v in d.items()], axis=1)
print(res)
A B
0 1.0 1
1 2.0 2
2 NaN 3
3 NaN 4
Ответ 6
Обе следующие строки работают отлично:
pd.DataFrame.from_dict(df, orient='index').transpose() #A
pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in df.items() ])) #B (Better)
Но с% timeit на Jupyter у меня есть соотношение скорости 4x для B против A, что весьма впечатляет, особенно при работе с огромным набором данных (в основном с большим количеством столбцов/функций).
Ответ 7
Если вы не хотите, чтобы он отображал NaN
, и у вас есть две конкретные длины, добавление "пробела" в каждую оставшуюся ячейку также будет работать.
import pandas
long = [6, 4, 7, 3]
short = [5, 6]
for n in range(len(long) - len(short)):
short.append(' ')
df = pd.DataFrame({'A':long, 'B':short}]
# Make sure Excel file exists in the working directory
datatoexcel = pd.ExcelWriter('example1.xlsx',engine = 'xlsxwriter')
df.to_excel(datatoexcel,sheet_name = 'Sheet1')
datatoexcel.save()
A B
0 6 5
1 4 6
2 7
3 3
Если у вас есть более 2 длин записей, рекомендуется создать функцию, которая использует аналогичный метод.