fillna problem

pandas.DataFrame has a fillna function which is highly useful for as a compliment to outer joins. gurobipy doesn't play as nicely as it could with this function, because it won't allow a Var to be the argument to fillna.

This is particularly relevant here because gurobipy also has the toehold problem (discussed in the notebook in the parent directory to this one).


In [1]:
from gurobipy import *
import  pandas as pd
m = Model()
v = m.addVar()
m.update()
df = pd.DataFrame({"a":[1, 2, 3], 
                   "b":[4, 5, 6], 
                   "data":[1, 12, 19]})
df.set_index(["a", "b"], inplace=True)
df2 = pd.DataFrame({"a":[1, 2, 5], "b" : [4, 5, 2], "data":[1.1, 12.1, 19]})
df2.set_index(["a", "b"], inplace=True)

Ok, set up finished, here is the buggy step.


In [2]:
df.join(df2, how="outer", rsuffix="_2").fillna(v)


---------------------------------------------------------------------------
GurobiError                               Traceback (most recent call last)
<ipython-input-2-6cb55fce6c25> in <module>()
----> 1 df.join(df2, how="outer", rsuffix="_2").fillna(v)

/Users/petercacioppi/anaconda/lib/python2.7/site-packages/pandas/core/frame.pyc in fillna(self, value, method, axis, inplace, limit, downcast, **kwargs)
   2703                                              axis=axis, inplace=inplace,
   2704                                              limit=limit, downcast=downcast,
-> 2705                                              **kwargs)
   2706 
   2707     @Appender(_shared_docs['shift'] % _shared_doc_kwargs)

/Users/petercacioppi/anaconda/lib/python2.7/site-packages/pandas/core/generic.pyc in fillna(self, value, method, axis, inplace, limit, downcast)
   2836                                              downcast=downcast)
   2837 
-> 2838             elif isinstance(value, (dict, com.ABCSeries)):
   2839                 if axis == 1:
   2840                     raise NotImplementedError('Currently only can fill '

/Users/petercacioppi/anaconda/lib/python2.7/site-packages/pandas/core/common.pyc in _check(cls, inst)
     69     @classmethod
     70     def _check(cls, inst):
---> 71         return getattr(inst, attr, '_typ') in comp
     72     dct = dict(__instancecheck__=_check,
     73                __subclasscheck__=_check)

var.pxi in gurobipy.Var.__getattr__ (../../src/python/gurobipy.c:11793)()

var.pxi in gurobipy.Var.getAttr (../../src/python/gurobipy.c:12304)()

GurobiError: Unknown attribute '_typ'

I'm inclined to think of this as something gurboipy can fix. Note how I can combine fillna with new style classes just fine. (I.e. see below).


In [3]:
class MyClass(object):
    def __repr__(self):
        return "<I made this class>"
mc = MyClass()

In [4]:
df.join(df2, how="outer", rsuffix="_2").fillna(mc)


Out[4]:
data data_2
a b
1 4 1 1.1
2 5 12 12.1
3 6 19 <I made this class>
5 2 <I made this class> 19

However, the most likely usage pattern is where I want not a variable but instead a gurobipy friendly proxy for zero. Luckily, that does work!


In [5]:
df.join(df2, how="outer", rsuffix="_2").fillna(quicksum([]))


Out[5]:
data data_2
a b
1 4 1 1.1
2 5 12 12.1
3 6 19 <gurobi.LinExpr: 0.0>
5 2 <gurobi.LinExpr: 0.0> 19

This is the workaround I use in the netflowpandasmodel.py file in this directory.

It also leads to the more general workaround - which is to use a linear expression equivalent to the variable itself. I.e. you can always call fillna(2*v-v) instead of fillna(v).


In [6]:
df.join(df2, how="outer", rsuffix="_2").fillna(2*v-v)


Out[6]:
data data_2
a b
1 4 1 1.1
2 5 12 12.1
3 6 19 <gurobi.LinExpr: 2.0 C0 + -1.0 C0>
5 2 <gurobi.LinExpr: 2.0 C0 + -1.0 C0> 19