Creating an element-wise minimum Series from two other Series in Python Pandas

PythonPandas

Python 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

I find this the simplest:

import numpy as np

smax = np.minimum(s1, s2)

Link to docs (numpy.minimum)

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2464433View Question on Stackoverflow
Solution 1 - PythonBrenBarnView Answer on Stackoverflow
Solution 2 - PythonAnkur KanoriaView Answer on Stackoverflow
Solution 3 - PythonAndy HaydenView Answer on Stackoverflow
Solution 4 - PythonfeaturedpeowView Answer on Stackoverflow
Solution 5 - PythonshanebView Answer on Stackoverflow
Solution 6 - PythonshanebView Answer on Stackoverflow
Solution 7 - Pythonrenan-eccelView Answer on Stackoverflow
Solution 8 - PythonMartin ThomaView Answer on Stackoverflow
Solution 9 - PythonMaxim EgorushkinView Answer on Stackoverflow