Панды: преобразовать 2D-фрейм данных в 3D-фрейм - PullRequest
2 голосов
/ 23 октября 2019

У меня есть кадр данных Pandas, например:

     p1 p2 p3
t1   a  b  c
t2   d  e  f
t3   g  h  i

, и я хочу либо несколько df (или один xarray), по одному для каждого t (ось y), например:

для t1:значение pn минус pn для t1:

     p1    p2   p3
p1   a-a  b-a  c-a 
p2   a-b  b-b  c-b
p3   a-c  b-c  c-c

то же самое для t2, t3 и так далее ...

Я сделал цикл, подобный

for t in tlist :
    for p in plist :
        for q in plist :
            res = p - q

но он скромный и медленный.

Так что, если кто-нибудь знает питонский способ сделать это, он очень рад!

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

Это можно сделать довольно простым способом, используя вещание * numpy . Давайте попробуем использовать следующий ndarray:

a = np.random.randint(1,10,(3,3))

print(a)
array([[9, 6, 4],
       [2, 3, 6],
       [8, 9, 2]])

a[:,None] - a[...,None]

array([[[ 0, -3, -5],
        [ 3,  0, -2],
        [ 5,  2,  0]],

       [[ 0,  1,  4],
        [-1,  0,  3],
        [-4, -3,  0]],

       [[ 0,  1, -6],
        [-1,  0, -7],
        [ 6,  7,  0]]])

Это работает путем добавления новых осей к массивам таким образом, что вычитание их приводит к требуемой декартовой операции, поскольку:

print(a[:,None])

array([[[9, 6, 4]],

       [[2, 3, 6]],

       [[8, 9, 2]]])

print(a[...,None])

array([[[9],
        [6],
        [4]],

       [[2],
        [3],
        [6]],

       [[8],
        [9],
        [2]]])
2 голосов
/ 23 октября 2019

Это можно сделать с помощью трансляции:

df = pd.DataFrame([[0,1,2],[3,6,8]])

# update as commented by piRSquared
a = df.to_numpy()    # use a=df.values if on Pandas < 0.24

a  = (a[:, None, :] - a[:,:,None]).reshape(-1, df.shape[1])

idx = pd.MultiIndex.from_product((df.index,df.columns), names=('t','p'))
pd.DataFrame(a, index=idx, columns=df.columns)

Вывод:

     0  1  2
t p         
0 0  0  1  2
  1 -1  0  1
  2 -2 -1  0
1 0  0  3  5
  1 -3  0  2
  2 -5 -2  0
...