Try setting emailconditions like so:
emailconditions = [
dfFinal['EmailC'].notna(),
dfFinal['EmailC'].isna() & dfFinal['EmailB'].notna(),
dfFinal['EmailC'].isna() & dfFinal['EmailB'].isna()]
Key point is to use notna() instead of is not None and isna() instead of is None.
Try setting emailconditions like so:
emailconditions = [
dfFinal['EmailC'].notna(),
dfFinal['EmailC'].isna() & dfFinal['EmailB'].notna(),
dfFinal['EmailC'].isna() & dfFinal['EmailB'].isna()]
Key point is to use notna() instead of is not None and isna() instead of is None.
Here's an alternative solution, which grabs the first truthy value out of the columns in whichever priority order you want:
In [3]: df
Out[3]:
a b c
0 x w None
1 None y None
2 k None z
In [4]: order = ("c", "b", "a")
In [5]: df.apply(lambda row: next(row[col] for col in order if row[col]), axis=1)
Out[5]:
0 w
1 y
2 z
dtype: object
If you anticipate having rows where none of the columns have a value, then you'd probably want something like this:
def first_truthy(row, order):
try:
return next(row[col] for col in order if row[col])
except StopIteration:
return None
Output:
In [7]: df
Out[7]:
a b c
0 x w None
1 None y None
2 k None z
3 None None None
In [8]: df.apply(lambda row: first_truthy(row, order), axis=1)
Out[8]:
0 w
1 y
2 z
3 None
dtype: object
Not that this is likely slower than boolean masking, but (in my opinion) easier to reason about and debug, and doesn't require the extra dependency on numpy. If you need performance, @richardec's solution is likely vastly superior, though I have not benchmarked our solutions.
Your expression works if you add parentheses:
>>> y[(1 < x) & (x < 5)]
array(['o', 'o', 'a'],
dtype='|S1')
IMO OP does not actually want np.bitwise_and() (aka &) but actually wants np.logical_and() because they are comparing logical values such as True and False - see this SO post on logical vs. bitwise to see the difference.
>>> x = array([5, 2, 3, 1, 4, 5])
>>> y = array(['f','o','o','b','a','r'])
>>> output = y[np.logical_and(x > 1, x < 5)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
dtype='|S1')
And equivalent way to do this is with np.all() by setting the axis argument appropriately.
>>> output = y[np.all([x > 1, x < 5], axis=0)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
dtype='|S1')
by the numbers:
>>> %timeit (a < b) & (b < c)
The slowest run took 32.97 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 1.15 µs per loop
>>> %timeit np.logical_and(a < b, b < c)
The slowest run took 32.59 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.17 µs per loop
>>> %timeit np.all([a < b, b < c], 0)
The slowest run took 67.47 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 5.06 µs per loop
so using np.all() is slower, but & and logical_and are about the same.