Vectorized way of checking dataframe values (as key, value tuple) against a dictionary?

I’d like to create a column in my dataframe that checks whether the values in one column are the dictionary values of another column which comprises the dictionary keys, like so:

In [3]:
df = pd.DataFrame({'Model': ['Corolla', 'Civic', 'Accord', 'F-150'],
                   'Make': ['Toyota', 'Honda', 'Toyota', 'Ford']})
dic = {'Prius':'Toyota', 'Corolla':'Toyota', 'Civic':'Honda', 
       'Accord':'Honda', 'Odyssey':'Honda', 'F-150':'Ford', 
       'F-250':'Ford', 'F-350':'Ford'}
df

Out [3]:
     Model    Make
0  Corolla  Toyota
1    Civic   Honda
2   Accord  Toyota
3    F-150    Ford

And after applying a function, or whatever it takes, I’d like to see:

Out [10]:
     Model    Make   match
0  Corolla  Toyota    TRUE
1    Civic   Honda    TRUE
2   Accord  Toyota   FALSE
3    F-150    Ford    TRUE

Thanks in advance!

Edit: I tried making a function that is passed a tuple which would be the two columns, but I don’t think I’m passing the arguments correctly:

def is_match(make, model):
  try:
    has_item = dic[make] == model
  except KeyError:
    has_item = False
  return(has_item)

df[['Model', 'Make']].apply(is_match)

results in:
TypeError: ("is_match() missing 1 required positional 
argument: 'model'", 'occurred at index Model')

Solution:

You can using map

df.assign(match=df.Model.map(dic).eq(df.Make))
Out[129]: 
     Make    Model  match
0  Toyota  Corolla   True
1   Honda    Civic   True
2  Toyota   Accord  False
3    Ford    F-150   True

Edit boolean and operator

So I’ve been messing around with the standard operators in classes to try and see what i can make, but i haven’t been able to find how to edit the boolean and operator.

I can edit the bitwise &operator by defining __and__(self), but not the way that and behaves. Does anyone know how I can change the behavior of a and b where a and bare instances of the class I’m making?

Thanks in advance!

Solution:

In Python 2, and and or access __nonzero__:

>>> class Test(object):
...     def __nonzero__(self):
...         print '__nonzero__ called'
...         return True
... 
>>> Test() and 1
__nonzero__ called
1

In Python 3, __nonzero__ has been renamed to __bool__.

>>> class Test:
...     def __bool__(self):
...         print('__bool__ called')
...         return True
... 
>>> Test() and 1
__bool__ called
1

Note that short-circuit evaluation might suppress a call to __nonzero__ or __bool__.

>>> 0 and Test()
0
>>> 1 or Test()
1

Another speciality to be aware of is that Python is trying to access __len__ if __nonzero__ / __bool__ is not defined and treats the object as truthy if __len__ returns a value other than 0. If both methods are defined, __nonzero__ / __bool__ wins.

>>> class Test:
...     def __len__(self):
...         return 23
... 
>>> Test() and True
True
>>>
>>> class Test:
...     def __len__(self):
...         return 23
...     def __bool__(self):
...         return False
... 
>>> Test() and True
<__main__.Test object at 0x7fc18b5e26d8> # evaluation stops at Test() because the object is falsy
>>> bool(Test())
False

Is there any way i can have this return something other than a bool, like, say, a list of bools?

Unfortunately, no. The documentation states that the method should return False or True but in fact you get a TypeError if you let it return something else.

>>> class Test:
...     def __bool__(self):
...         return 1
... 
>>> Test() and 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __bool__ should return bool, returned int
>>> 
>>> bool(Test())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __bool__ should return bool, returned int