I am trying to calculate the following formula:
I wrote this to calulate this:
%%timeit
df = pd.DataFrame(columns=["h","i","j","k"])
x1=10
y1=8
m=7
P_List = []
m_range = np.arange(0,m+1)
for m in m_range:
df = pd.DataFrame(columns=["h","i","j","k"])
h_range = np.arange(0,x1+1)
for h in h_range:
if (x1-h)>=0:
i_range = np.arange(0,x1-h+1)
else:
break
for i in i_range:
if (y1-(m-i))>=0:
k_range = np.arange(0,y1-(m-i)+1)
else:
break
j = m-i
if j>=0:
for k in k_range:
arguments = { "h":h, "i":i, "j":j, "k":k}
df = df.append(arguments, ignore_index=True)
df["P"]= df.apply(lambda x: cal_P(x), axis=1)
P_List.append(df.P.sum())
Output: 5 s ± 184 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Another way to do this:
%%timeit
df = pd.DataFrame(columns=["h","i","j","k"])
x1=10
y1=8
m=7
P_List = []
m_range = np.arange(0,m+1)
for m in m_range:
h_range = np.arange(0,x1+1)
i_range = np.arange(0,x1+1)
k_range = np.arange(0,y1+x1+2)
j_range = np.arange(0,x1+m+1)
data = np.array(np.meshgrid( h_range, i_range, k_range, j_range)).T.reshape(-1,4)
df = pd.DataFrame(data=data, columns=[ "h","i","j","k"])
i_cond = df.i<=(x1-df.h) #(x1-h)
k_cond = df.k<=(y1-(m-df.i)) #(y1-(m-i))
j_cond = df.j == (m-df.i)
df = df.drop(df[~(i_cond&k_cond&j_cond)].index)
df["P"]= df.apply(lambda x: cal_P(x), axis=1)
P_List.append(df.P.sum())
Output: 306 ms ± 5.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Now the problem is that the value of x1, y1, and m is very large for my dataset. For the largest dataset, x1≈2000, y1≈1800, m≈500. So the 1st method is running forever, while the second method is running out of memory.
Is there anyway to do this faster without running out of memory? Or any other better way to calculate the above formula?
Edit:
P calculates the hypergeometric distribution for a value of m. I have updated the above code to reflect that.
where,
The 3-element trinomial function (a,b,c)! defined as:

For timing it cal_Pis
def cal_P(row):
l = row.h+row.i+row.j+row.k
return l
But the actual code to calculate the hypergeometric distribution is:
from math import factorial as fact
def t_func(a,b,c):
d=a-b-c
if d>=0 and a>=0 and b>=0 and c>=0:
result = fact(a)/(fact(b)*fact(c)*fact(d))
else:
result = 0
return result
def hypergeom_XY(h, i, j, k, x1, x2, y1, y2, l):
pmf = t_func(x1,h,i)*t_func(y1,j,k)*t_func(l-x1-y1,x2-h-j,y2-i-k)/t_func(l,x2,y2)
return pmf
def cal_P(row):
P = hypergeom_XY(row.h, row.i, row.j, row.k, x1, x2, y1, y2, l)
return P
