Построение 3D Pandas DataFrame
Мне сложно создать 3D-DataFrame в Pandas. Я хочу что-то вроде этого
A B C
start end start end start end ...
7 20 42 52 90 101
11 21 213 34
56 74 9 45
45 12
Где A
, B
и т.д. дескрипторы верхнего уровня и start
и end
являются поддекрипторами. Следующие числа находятся в парах и не существует одинакового числа пар для A
, B
и т.д. Заметим, что A
имеет четыре таких пары, B
имеет только 1, а C
имеет 3.
Я не уверен, как приступить к построению этого DataFrame. Модификация этого примера не дала мне спроектированного вывода:
import numpy as np
import pandas as pd
A = np.array(['one', 'one', 'two', 'two', 'three', 'three'])
B = np.array(['start', 'end']*3)
C = [np.random.randint(10, 99, 6)]*6
df = pd.DataFrame(zip(A, B, C), columns=['A', 'B', 'C'])
df.set_index(['A', 'B'], inplace=True)
df
дали:
C
A B
one start [22, 19, 16, 20, 63, 54]
end [22, 19, 16, 20, 63, 54]
two start [22, 19, 16, 20, 63, 54]
end [22, 19, 16, 20, 63, 54]
three start [22, 19, 16, 20, 63, 54]
end [22, 19, 16, 20, 63, 54]
Есть ли способ разбивать списки в C на свои собственные столбцы?
EDIT: важна структура моего C
. Он выглядит следующим образом:
C = [[7,11,56,45], [20,21,74,12], [42], [52], [90,213,9], [101, 34, 45]]
И желаемый результат - тот, что находится наверху. Он представляет начальную и конечную точки подпоследовательностей в определенной последовательности (A
, B
. C
- это разные последовательности). В зависимости от самой последовательности существует различное количество подпоследовательностей, удовлетворяющих заданному условию, которое я ищу. В результате существует различное количество начальных: пар торцов для A
, B
и т.д.
Ответы
Ответ 1
Во-первых, я думаю, вам нужно заполнить C, чтобы представить отсутствующие значения
In [341]: max_len = max(len(sublist) for sublist in C)
In [344]: for sublist in C:
...: sublist.extend([np.nan] * (max_len - len(sublist)))
In [345]: C
Out[345]:
[[7, 11, 56, 45],
[20, 21, 74, 12],
[42, nan, nan, nan],
[52, nan, nan, nan],
[90, 213, 9, nan],
[101, 34, 45, nan]]
Затем преобразуйте в массив numpy, транспонируйте и перейдите к конструктору DataFrame вместе с столбцами.
In [288]: C = np.array(C)
In [289]: df = pd.DataFrame(data=C.T, columns=pd.MultiIndex.from_tuples(zip(A,B)))
In [349]: df
Out[349]:
one two three
start end start end start end
0 7 20 42 52 90 101
1 11 21 NaN NaN 213 34
2 56 74 NaN NaN 9 45
3 45 12 NaN NaN NaN NaN
Ответ 2
Не можете ли вы просто использовать панель?
import numpy as np
import pandas as pd
A = ['one', 'two' ,'three']
B = ['start','end']
C = [np.random.randint(10, 99, 2)]*6
df = pd.DataFrame(C,columns=B )
p={}
for a in A:
p[a]=df
panel= pd.Panel(p)
print panel['one']
Ответ 3
Как упомянул @Aaron в комментарии выше, панели устарели. Кроме того, @tlnagy отметил, что его набор данных в будущем может расшириться до более чем трех измерений.
Это звучит как хороший пример использования пакета xarray, который предоставляет семантически помеченные массивы произвольного числа измерений. Панды и xarray имеют сильную поддержку преобразования, а панели были устаревшими в пользу использования xarray.
Начальная настройка проблемы.
import numpy as np
A = np.array([[7,11,56,45], [20,21,74,12]]).T
B = np.array([[42], [52]]).T
C = np.array([[90,213,9], [101, 34, 45]]).T
Затем вы можете создать трехмерный объект xarray.DataArray следующим образом:
import xarray
output_as_dataarray = xarray.concat(
[xarray.DataArray(X,
dims=['record', 'edge'],
coords={'record': range(X.shape[0]),
'edge': ['start', 'end']},
) for X in (A, B, C)],
dim='descriptor',
).assign_coords(descriptor=['A', 'B', 'C'])
Мы превращаем наши три двумерных массива в объекты xarray.DataArray, а затем объединяем их вместе в новом измерении.
Наш вывод выглядит так:
<xarray.DataArray (descriptor: 3, record: 4, edge: 2)>
array([[[ 7., 20.],
[ 11., 21.],
[ 56., 74.],
[ 45., 12.]],
[[ 42., 52.],
[ nan, nan],
[ nan, nan],
[ nan, nan]],
[[ 90., 101.],
[213., 34.],
[ 9., 45.],
[ nan, nan]]])
Coordinates:
* record (record) int64 0 1 2 3
* edge (edge) <U5 'start' 'end'
* descriptor (descriptor) <U1 'A' 'B' 'C'