2012-08-24 10 views
5

Esistono funzioni integrate che consentono operazioni elementwise su tuple in Python 3? In caso contrario, qual è il modo "pitonico" per eseguire queste operazioni?Operazioni elementari su tuple in Python

Esempio: voglio prendere la differenza percentuale tra a e b e confrontarli con qualche soglia th.

>>> a = (1, 2, 4) 
>>> b = (1.1, 2.1, 4.1) 
>>> # compute pd = 100*abs(a-b)/a = (10.0, 5.0, 2.5) 
>>> th = 3 
>>> # test threshold: pd < th => (False, False, True) 
+0

stiamo parlando della funzione mappa? http://docs.python.org/release/3.1.5/library/functions.html#map – bpgergo

+0

combinato con zip? http://docs.python.org/release/3.1.5/library/functions.html#zip – bpgergo

risposta

5

funzione mappa

>>> a = (1, 2, 4) 
>>> b = (1.1, 2.1, 4.1) 
>>> map(lambda a,b: 100*abs(a-b)/a < 3, a, b) 
[False, False, True] 

EDIT

naturalmente, invece di mappa, è possibile utilizzare list comprehension, come BrenBarn fatto http://docs.python.org/tutorial/datastructures.html#nested-list-comprehensions

EDIT 2 zip rimosso, grazie per il DSM per farlo notare che la chiusura lampo non è necessario

+2

Non hai bisogno di 'zip' qui; potresti scrivere 'map (lambda a, b: 100 * abs (a-b)/a <3, a, b)'. [Nota questa funzione accetta due argomenti, non una tupla da 2.] – DSM

+0

'map (lambda (a, b): 100 * abs (ab)/a <3, a, b)' => 'TypeError: () prende esattamente 1 argomento (2 dato) ' – bpgergo

+0

@DSM Potrebbe ma forse non dovrebbe. Detesto le scorciatoie che consentono di unire un'altra funzione di ordine superiore in un'altra tramite overload (molto comune in LINQ, ad esempio '.First (cond)' invece di '.Where (cond) .First()'), perché non è mai ovvio a me * quale * operazione è implicita (map? zip? filter? qualcos'altro?). – delnan

1

Non sono a conoscenza di un'operazione del genere, forse alcune delle funzioni di programmazione funzionali di Python avrebbe funzionato (mappa? Ridurre?), Anche se mettere insieme un list comprehension (o generatore se non è necessaria la lista) è relativamente semplice:

[100*abs(j-b[i])/j < 3 for i,j in enumerate(a)] 
[False, False, True] 

Grazie a @delnan per aver ricordato una bella semplificazione per la versione originale, più esplicito/verbose:

[True if 100*abs(j-b[i])/j < 3 else False for i,j in enumerate(a)] 
+3

'True se 100 * abs (jb [i])/j <3 else False' ->' 100 * abs (jb [i])/j <3' – delnan

+0

@delnan Ah .. capito! Molto bella!! .. grazie, aggiornerò la risposta. – Levon

+0

@delnan 'bool' non sembra necessario – Levon

9

Non c'è modo integrato, ma c'è un modo molto semplice:

[f(aItem, bItem) for aItem, bItem in zip(a, b)] 

. . . dove f è la funzione che si desidera applicare elementwise. Per il vostro caso:

[100*abs(aItem - bItem)/aItem < 3 for aItem, bItem in zip(a, b)] 

Se vi trovate a fare questo molto, soprattutto con lunghe tuple, si potrebbe desiderare di guardare Numpy, che fornisce un sistema completo di operazioni vettoriali in cui molte funzioni comuni di vettore (operazioni di base, funzioni trigonometriche, ecc.) si applicano elementwise.

+1

+1 per suggerire numpy –

0

Direi che il modo in cui Pythonic è con la lista di comprensione:

Quando a = (1, 2, 4) e b = (1.1, 2.1, 4.1)

poi, in una sola riga:

TEST = [100*abs(a[i]-b[i])/a[i] > th for i in range(len(A))] 
+0

Questo valuterà il fn sul prodotto cartesiano di A e B, non elementwise. – DSM

+0

@DSM oops, corretto. –

0
def pctError(observed, expected): 
    return (observed-expected)/expected * 100.0 

a = (1, 2, 4) 
b = (1.1, 2.1, 4.1) 
th = 3 

pctErrors = map(lambda t:pctError(*t), zip(a,b)) 
# returns [-9.091, -4.76, -2.44] 

map(lambda x: x < th, pctErrors) 
[x < th for x in pctErrors] 
# both return [True, True, True] 

# or if you always need absolute % errors 
map(lambda x: abs(x) < th, pctErrors) 
[abs(x) < th for x in pctErrors] 
# both return [False, False, True] 
4

Perché non usare NumPy?

import numpy as np 
a = np.array([1,2,4]) 
b = np.array([1.1, 2.1, 4.1]) 

pd = 100*abs(a-b)/a # result: array([ 10. , 5. , 2.5]) 
th = 3 
pd < th # result: array([False, False, True], dtype=bool)