You can simply use:
b = a[np.all(a[:,:3] < 0,axis=1)]
So you can first construct a submatrix by using slicing a[:,:3] will construct a matrix for the first three columns of the matrix a. Next we use < 0 to check if all these elements are less than zero.
We then will perform a logical and on every row (by anding the columns together). This will construct a 1D matrix for every row. An element will be True if all the three columns are True. Otherwise it is False.
Finally we use masking to construct a submatrix where the first three columns are all less than 0. This will probably work faster since the number of numpy calls is less and thus we do more work per call.
Answer from willeM_ Van Onsem on Stack OverflowAs Toan suggests, a simple hack would be to just select the rows first, and then select the columns over that.
>>> a[[0,1,3], :] # Returns the rows you want
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[12, 13, 14, 15]])
>>> a[[0,1,3], :][:, [0,2]] # Selects the columns you want as well
array([[ 0, 2],
[ 4, 6],
[12, 14]])
[Edit] The built-in method: np.ix_
I recently discovered that numpy gives you an in-built one-liner to doing exactly what @Jaime suggested, but without having to use broadcasting syntax (which suffers from lack of readability). From the docs:
Using ix_ one can quickly construct index arrays that will index the cross product.
a[np.ix_([1,3],[2,5])]returns the array[[a[1,2] a[1,5]], [a[3,2] a[3,5]]].
So you use it like this:
>>> a = np.arange(20).reshape((5,4))
>>> a[np.ix_([0,1,3], [0,2])]
array([[ 0, 2],
[ 4, 6],
[12, 14]])
And the way it works is that it takes care of aligning arrays the way Jaime suggested, so that broadcasting happens properly:
>>> np.ix_([0,1,3], [0,2])
(array([[0],
[1],
[3]]), array([[0, 2]]))
Also, as MikeC says in a comment, np.ix_ has the advantage of returning a view, which my first (pre-edit) answer did not. This means you can now assign to the indexed array:
>>> a[np.ix_([0,1,3], [0,2])] = -1
>>> a
array([[-1, 1, -1, 3],
[-1, 5, -1, 7],
[ 8, 9, 10, 11],
[-1, 13, -1, 15],
[16, 17, 18, 19]])
Fancy indexing requires you to provide all indices for each dimension. You are providing 3 indices for the first one, and only 2 for the second one, hence the error. You want to do something like this:
>>> a[[[0, 0], [1, 1], [3, 3]], [[0,2], [0,2], [0, 2]]]
array([[ 0, 2],
[ 4, 6],
[12, 14]])
That is of course a pain to write, so you can let broadcasting help you:
>>> a[[[0], [1], [3]], [0, 2]]
array([[ 0, 2],
[ 4, 6],
[12, 14]])
This is much simpler to do if you index with arrays, not lists:
>>> row_idx = np.array([0, 1, 3])
>>> col_idx = np.array([0, 2])
>>> a[row_idx[:, None], col_idx]
array([[ 0, 2],
[ 4, 6],
[12, 14]])
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.
One way to get an R-like syntax here would be to use np.r_:
>>> Z = np.arange(2000).reshape(20, 100)
>>> Z.shape
(20, 100)
>>> x = Z[:,np.r_[:49,50:100]]
>>> x.shape
(20, 99)
>>> x[0,48:52]
array([48, 50, 51, 52])
and we see that the 50th column (with number 49) is missing from x.
This would work:
>>> a = np.arange(2000).reshape(20, 100)
>>> b = a[:, np.arange(a.shape[1]) != 50]
>>> b.shape
(20, 99)