1

I've looked it over several times, but still can't understand what seems to be wrong here. This is the cosine similarity function written below, and also where its called with 2 vectors.

def cosine_sim(v1, v2):
     return (lambda x,y,z: x / sqrt(y * z))(reduce(lambda x,y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1,v2),(0,0,0)))

cosine_sim(first_vector,second_vector)

Error:


TypeError Traceback (most recent call last) in () ----> 1 cosine_sim(firstvector,secondvector)

in cosine_sim(v1, v2) 1 def cosine_sim(v1, v2): ----> 2 return (lambda x,y,z: x / sqrt(y * z))(reduce(lambda x,y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1,v2),(0,0,0)))

TypeError: () missing 2 required positional arguments: 'y' and 'z'

Eugene Wolf
  • 69
  • 1
  • 5
  • 1
    You're calling the first lambda function, `lambda x,y,z: x / sqrt(y * z)`, on the single tuple `(reduce(lambda x,y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1,v2),(0,0,0))`, so x is a 3-element tuple and y and z are undefined. But also, why does this need to be a one-liner with multiple anonymous functions?? –  Nov 24 '18 at 04:53

1 Answers1

3

Your reduce call returns a three-tuple, so you're calling your lambda x, y, z with x as that three-tuple, and no arguments for y or z.

The simplest fix is to use the splat operator, *, to unpack the return from reduce so the three-tuple is converted to three sequential positional arguments:

def cosine_sim(v1, v2):
    return (lambda x,y,z: x / sqrt(y * z))(*reduce(lambda x,y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1,v2),(0,0,0)))
    #                       change is here ^

Note that one-lining this is ugly as hell, and you're likely better off making it (at least) a two-liner, just to reduce complexity. Even keeping reduce, you could simplify a little to just:

def cosine_sim(v1, v2):
    x, y, z = reduce(lambda x,y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1,v2),(0,0,0))
    return x / sqrt(y * z)

which is basically what your lambda was attempting, but with lower overhead (no need to call more functions for no reason).

Removing reduce entirely would make it slightly longer, but again, easier to interpret:

def cosine_sim(v1, v2):
    x = y = z = 0
    for a, b in izip(v1, v2):
        x += a * b
        y += a ** 2
        z += b ** 2
    return x / sqrt(y * z)

Give better names to the variables if possible, and this is pretty decent code (and likely faster to boot).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271