2016-01-28 12 views
8

Dikdörtgenlerim var (kare olarak kabul edilemez) Pandas DataFrame sayılar. Köşegen bir yön seçtiğimi ("üst yarıçaptan alçağa doğru" veya "üst kısma indir") diyorum. Girişleri, seçili paralel köşegen dizisi boyunca orijinal DataFrame'deki değerlerin toplamı olan bir dizi hesaplamak istiyorum. Hedefi tam olarak belirtmek için, köşegenlerin solda "demirlemiş" olup olmadığına veya sağda "demir atılmış" olup olmadığına karar vermelisiniz. Aşağıda, solda "demirlemiş" olduklarını farz ediyorum.Numpy/Pandalar'daki tüm paralel köşegenlerin toplamını oluşturmanın doğrudan yolu?

import numpy as np 
import pandas as pd 

rectdf = pd.DataFrame(np.arange(15).reshape(5,3)) 

# result: 
    0 1 2 
0 0 1 2 
1 3 4 5 
2 6 7 8 
3 9 10 11 
4 12 13 14 

ben şöyle diyagonal toplamları "upperleft lowerright için" hesaplayabiliriz:

ben çok fazla sorun olmadan yapabilirsiniz

ullrsums = pd.concat([rectdf.iloc[:, i].shift(-i) for i in range(rectdf.shape[1])], axis=1)\ 
    .sum(axis=1, fillna=0) 

# result: 
0 12 
1 21 
2 30 
3 22 
4 12 

Ve hesaplayabilir "upperright lowerleft için "önceki içinde shift(i) için shift(-i) saygısız diyagonal toplamlar:

urllsums = pd.concat([rectdf.iloc[:, i].shift(i) for i in range(rectdf.shape[1])], axis=1)\ 
    .sum(axis=1, fillna=0) 

# result: 
0  0 
1  4 
2 12 
3 21 
4 30 

Bu sonuçların tümü doğrudur (örn. Bu kod istediğimi yapar. Bu miktarları Pandalar veya Numpy'de hesaplamak için daha doğrudan bir yol var mı?

+0

İlgili: http://stackoverflow.com/q/10792897 ve http://stackoverflow.com/q/28917414 –

cevap

6
Sen numpy.trace() arıyor olabilir

, diyagonal vektörü elde etmek numpy.diagonal() doğrudan izleme almak, ya da, here belgelenmiş documented here

Öncelikle Sonra rectdf.as_matrix()

kullanarak numpy matrise sizin dataframe dönüştürmek:

np.trace(matrix, offset) 

Olumlu veya olumsuz olabilen ofset, istediğiniz kaydırmayı yapar.

çıkışını
a = np.arange(15).reshape(5, 3) 
for x in range(-4, 3): print np.trace(a, x) 

Biz olsun: Elimizdeki, biz yani -(rows - 1) den columns için aralık

12 
22 
30 
21 
12 
6 
2 

genel matris için Bunu yapmak için istediğiniz yaptığımız Örneğin

, bir değişken rows ve bir değişken columns:

0

Kısa yanıt

Sonunda hızlı ama karmaşık bir işleve bakın. trace üzerinde

gelişme

Yineleme iyidir, ama pandalar çözümü daha iyidir emin değilim. Her ikisi de yinelenen çapraz veya sütunlar içerir. Kavramsal olarak daha basit veya daha temiz, ancak özellikle büyük dizilerde hız konusunda emin değilim.

Her köşegenin farklı bir uzunluğu vardır, [[12],[9,13],...]. Bu büyük bir kırmızı bayrak, bize bir blok dizisi işleminin imkansız değilse zor olduğunu bildiriyor.

scipy.sparse ile yine bu izleri elde özetlenebilir 2d dizi gerçekleştirebilmesi:

In [295]: from scipy import sparse 
In [296]: xs=sparse.dia_matrix(x) 
In [297]: xs.data 
Out[297]: 
array([[12, 0, 0], 
     [ 9, 13, 0], 
     [ 6, 10, 14], 
     [ 3, 7, 11], 
     [ 0, 4, 8], 
     [ 0, 1, 5], 
     [ 0, 0, 2]]) 
In [298]: np.sum(xs.data,axis=1) 
Out[298]: array([12, 22, 30, 21, 12, 6, 2]) 

Bu seyrek biçimi gerekli vardiya ile, bir 2d dizisindeki data depolar.

data[row_indices, col_indices] = x.ravel() 

gibi bir şey:

In [344]: i=[4,5,6,3,4,5,2,3,4,1,2,3,0,1,2] 
In [345]: j=[0,1,2,0,1,2,0,1,2,0,1,2,0,1,2] 
In [346]: z=np.zeros((7,3),int) 
In [347]: z[i,j]=x.ravel()[:len(i)] 
In [348]: z 
Out[348]: 
array([[12, 0, 0], 
     [ 9, 13, 0], 
     [ 6, 10, 14], 
     [ 3, 7, 11], 
     [ 0, 4, 8], 
     [ 0, 1, 5], 
     [ 0, 0, 2]]) 

O sparse benziyor
In [304]: pd.concat([rectdf.iloc[:, i].shift(-i) for i in range(rectdf.shape[1])], axis=1) 
Out[304]: 
    0 1 2 
0 0 4 8 
1 3 7 11 
2 6 10 14 
3 9 13 NaN 
4 12 NaN NaN 

bir np.zeros ile başlayan ve uygun endeksleme ile doldurarak bu data dizi oluşturur: Aslında sizin pd.concat benzer bir şey üretir

Yine de herhangi bir şekil için i,j oluşturmanın bir yoluna ihtiyacım var. j için kolaydır: Yani arada

In [371]: ii=(np.arange(3)+np.arange(5)[::-1,None]).ravel() 
In [372]: ii 
Out[372]: array([4, 5, 6, 3, 4, 5, 2, 3, 4, 1, 2, 3, 0, 1, 2]) 

:

def all_traces(x): 
    jj = np.tile(np.arange(x.shape[1]),x.shape[0]) 
    ii = (np.arange(x.shape[1])+np.arange(x.shape[0])[::-1,None]).ravel() 
    z = np.zeros(((x.shape[0]+x.shape[1]-1),x.shape[1]),int) 
    z[ii,jj] = x.ravel() 
    return z.sum(axis=1) 

Daha ihtiyacı

j=np.tile(np.arange(3),5) 
j=np.tile(np.arange(x.shape[1]),x.shape[0]) 

i

In [363]: np.array(i).reshape(-1,3) 
Out[363]: 
array([[4, 5, 6], 
     [3, 4, 5], 
     [2, 3, 4], 
     [1, 2, 3], 
     [0, 1, 2]]) 

yeniden şekillendirme ile yeniden götürüyor çeşitli şekillerde test etme.

Bu fonksiyon bile bu küçük boyutlu dizisi ile, bu iz üzerinden yineleme daha hızlıdır:

In [387]: timeit all_traces(x) 
10000 loops, best of 3: 70.5 µs per loop 
In [388]: timeit [np.trace(x,i) for i in range(-(x.shape[0]-1),x.shape[1])] 
10000 loops, best of 3: 106 µs per loop 
0

bu olacak en kısa kod çapraz mesafelerinin toplamak için olabilecek bir 2D numpy dizide A için (?):

np.bincount(sum(np.indices(A.shape)).flat, A.flat) 

Ters köşegenleri toplamak için diziyi np.fliplr yapabilirsiniz.

İlgili konular