2016-01-28 11 views
8

मेरे पास एक आयताकार है (वर्ग के रूप में नहीं माना जा सकता है) संख्याओं के पांडस डेटाफ्रेम। मान लें कि मैं एक विकर्ण दिशा (या तो "ऊपरी बाएं से दाएं" या "ऊपरी दाएं कोने के लिए") चुनें। मैं एक श्रृंखला की गणना करना चाहता हूं, जिनकी प्रविष्टियां मूल डेटाफ्रेम से समानांतर विकर्णों के चुने हुए सेट के मूल्यों की रकम हैं। लक्ष्य को पूरी तरह से निर्दिष्ट करने के लिए, आपको यह तय करने की आवश्यकता है कि क्या विकर्ण बाईं ओर "एंकर" हैं या दाईं ओर "एंकर" हैं। नीचे के लिए, मुझे लगता है कि वे बाईं ओर "लंगर" हैं।Numpy/Pandas में सभी समानांतर विकर्णों के योग उत्पन्न करने का सीधा तरीका?

मैं बहुत अधिक परेशानी के बिना यह कर सकते हैं:

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 

मैं इस प्रकार है "upperleft lowerright को" विकर्ण रकम की गणना कर सकते हैं:

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 

और मैं गणना कर सकता है "upperright lowerleft को "पिछले में shift(i) करने के लिए shift(-i) flipping द्वारा विकर्ण रकम:

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 

ये परिणाम सभी सही हैं (यानी। यह कोड जो मैं चाहता हूं)। क्या पांडस या नम्पी में इन रकमों की गणना करने का कोई और सीधा तरीका है?

+0

संबंधित: http://stackoverflow.com/q/10792897 और http://stackoverflow.com/q/28917414 –

उत्तर

6

आप numpy.trace() की तलाश में हो सकता है, here प्रलेखित,, ट्रेस सीधे numpy.diagonal() प्राप्त करने के लिए, या विकर्ण वेक्टर पाने के लिए documented here

सबसे पहले, एक numpy मैट्रिक्स rectdf.as_matrix()

तब उपयोग करने के लिए अपने dataframe कन्वर्ट:

np.trace(matrix, offset) 

ऑफ़सेट, जो सकारात्मक या नकारात्मक हो सकता है, क्या आपको स्थानांतरण की आवश्यकता है।

उदाहरण के लिए

, अगर हम कार्य करें:

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

हम मिल उत्पादन:

12 
22 
30 
21 
12 
6 
2 

एक सामान्य मैट्रिक्स के लिए ऐसा करने के लिए, हम सीमा -(rows - 1) से columns करना चाहते हैं, यानी अगर हमारे पास एक चर rows और एक चर columns:

a = np.arange(rows * columns).reshape(rows, columns) 
for x in range(-(rows - 1), columns): print np.trace(a, x) 
0

संक्षिप्त उत्तर

अंत में तेज़, लेकिन जटिल कार्य देखें।

विकास

trace से अधिक पुनरावृत्ति अच्छा है, लेकिन मैं इसे पांडा समाधान की तुलना में बेहतर है यकीन नहीं है। दोनों में विकृतियां शामिल हैं - विकर्ण या स्तंभों पर। संकल्पनात्मक रूप से यह सरल या क्लीनर है, लेकिन मुझे गति के बारे में निश्चित नहीं है, खासकर बड़े सरणी पर।

प्रत्येक विकर्ण की एक अलग लंबाई है, [[12],[9,13],...]। यह एक बड़ा लाल झंडा है, हमें चेतावनी देता है कि अगर असंभव नहीं है तो ब्लॉक सरणी ऑपरेशन मुश्किल है।

scipy.sparse के साथ मैं एक 2d सरणी है कि इन निशान देने के लिए अभिव्यक्त किया जा सकता का निर्माण कर सकते हैं:

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]) 

यह विरल प्रारूप, एक 2d सरणी में अपनी data संग्रहीत करता आवश्यक बदलाव के साथ।

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

कुछ की तरह:

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]]) 

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 

यह sparse की तरह दिखता है एक np.zeros के साथ शुरू, और उचित अनुक्रमण के साथ इसे भर कर इस data सरणी बनाता है: वास्तव में अपने pd.concat कुछ इसी तरह का उत्पादन

हालांकि मुझे अभी भी किसी भी आकार के लिए i,j बनाने का एक तरीका चाहिए। j के लिए यह आसान है:

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) 

यह अधिक की जरूरत है

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

Reshaping 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]]) 

मेरे साथ पुनः बनाने की ओर जाता है विभिन्न आकारों पर परीक्षण।

इस समारोह, निशान से अधिक यात्रा की तुलना में तेजी है यहां तक ​​कि इस छोटे आकार सरणी के साथ:

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

एक 2D numpy सरणी A इस होना कम से कम कोड विकर्णों योग करने के लिए हो सकता है के लिए (?):

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

विपरीत विकर्णों को योग करने के लिए, आप np.fliplr सरणी कर सकते हैं।

संबंधित मुद्दे