Creating an element-wise minimum Series from two other Series in Python Pandas
PythonPandasPython Problem Overview
I am having trouble finding a way to do an efficient element-wise minimum of two Series objects in pandas. For example I can add two Series easily enough:
In [1]:
import pandas as pd
s1 = pd.Series(data=[1,1,1], index=[1,2,3])
s2 = pd.Series(data=[1,2,2,1], index=[1,2,3,4])
s1.add(s2)
Out[1]:
1 2
2 3
3 3
4 NaN
dtype: float64
But I cannot find an efficient way to do an element-wise minimum between two Series (along with aligning the indices and handling NaN values).
Nevermind. There is an escape hatch with the combine function so you can put in any element-wise function:
In [2]:
s1 = pd.Series(data=[1,1,1], index=[1,2,3])
s2 = pd.Series(data=[1,2,2,1], index=[1,2,3,4])
s1.combine(s2, min, 0)
Out[2]:
1 1
2 1
3 1
4 0
dtype: int64
Python Solutions
Solution 1 - Python
The most straightforward way I can see is to make them into a DataFrame and then take the row-wise min:
>>> print pandas.concat([s1, s2], axis=1).min(axis=1)
1 1
2 1
3 1
4 1
dtype: float64
Solution 2 - Python
Solution 3 - Python
Another similar way:
In [11]: pd.DataFrame([s1, s2]).min()
Out[11]:
1 1
2 1
3 1
4 1
dtype: float64
Solution 4 - Python
pd.Series([1,2,3,4,5]).clip(upper=pd.Series([6,5,4,3,2]))
will get you:
0 1
1 2
2 3
3 3
4 2
dtype: int64
Solution 5 - Python
You can concat the dataframes and take the minimum, specifying level=0
:
>>> s1 = pd.Series(data=[1,1,1], index=[1,2,3])
>>> s2 = pd.Series(data=[1,2,2,1], index=[1,2,3,4])
>>> pd.concat([s1, s2]).min(level=0)
1 1
2 1
3 1
4 1
dtype: int64
This approach also works on dataframes.
Solution 6 - Python
You can use the combine
method of a DataFrame with np.minimum
as the argument. np.minimum
has special handling for NaN and complex NaNs.
Indeed, the pandas docs for combine uses the np.minimum
function to illustrate a "true element-wise combine":
>>> df1 = pd.DataFrame({'A': [5, 0], 'B': [2, 4]})
>>> df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
>>> df1.combine(df2, np.minimum)
A B
0 1 2
1 0 3
Solution 7 - Python
This method will do the job:
import pandas as pd
def elementwise_min(x, y):
x[x > y] = y
return x
a = pd.Series([1, 2, 3])
b = pd.Series([0, 2, 4])
elementwise_min(a, b)
Solution 8 - Python
Same answer as Andy Hayden, but a bit easier to read:
>>> import pandas as pd
>>> s1 = pd.Series(data=[1,2,3,4,5], index=[1,2,3,4,5])
>>> s2 = pd.Series(data=[5,1,3,5], index=[1,2,3,4])
>>> pd.DataFrame([s1, s2]).min()
1 1.0
2 1.0
3 3.0
4 4.0
5 5.0
dtype: float64
Solution 9 - Python
One straight-forward way is to use Series.where
function:
min_s1_s2 = s1.where(s1 < s2, s2)
where
is a fundamental method in terms of which clip
can be implemented, but not the other way around.