Getting stuck in a loop - python

I have written this code, but the problem is for large number for P and SLOT, the code will be stocked in a loop and unfortunately, I do not know how to fix this problem. I would be more than thankful if someone can help me to fix this problem.
I have attached the code below for your further review.
This code is for developing a patient scheduling system based on the patient no-show.
import pandas as pd
import numpy as np
import random
import datetime
SLOT = 12 # Number of slots per day
PHY = 2 # Number of Physicians
P = 36 # Number of Patients
number_OB = np.zeros((PHY, 1)) # Number of overbooked for each physician
Limit_OB = np.zeros((PHY, 1))
for i in range(Limit_OB.shape[0]):
Limit_OB[i] = 2 # Capacity of each physician is to visit maximum 2 patients in each slot
preference = [random.randint(1, 3) for i in range(P)] # patients' preference for seeing physician 1 and 2: Preference 3 means the patient has no preference for physician 1 or 2
noshowtype = [random.randint(0, 1) for i in range(P)] # 0 means the patient no-show is low and 1 means the patient no-show is high
availability = np.random.randint(2, size=(P,SLOT)) # This matrix shows the availability of each patients for each slot
# Initialization
print(preference)
print(len(preference))
print(noshowtype)
print(len(noshowtype))
print(availability)
availability.shape
totpat = np.zeros((PHY, SLOT))
tot_pat_sch = np.zeros((PHY,1))
assign = np.zeros(shape=(P, SLOT, PHY))
totpatslot = np.zeros((SLOT, 1))
noapp = np.zeros((P, 1))
put = np.zeros((P, SLOT))
unschedule = np.zeros((P,SLOT))
slotcap = [2,1,1,1,2,1,1,1,2,1,1,1]
totpatslot = [0,0,0,0,0,0,0,0,0,0,0,0]
tot_pat_sch = [0,0]
for p in range(P):
count = 0
if preference[p] == 3:
for phy in range(PHY):
for s in range(SLOT):
tot_pat_sch[phy] = tot_pat_sch[phy] + totpat[PHY-1,s]
if tot_pat_sch[0] == tot_pat_sch[1]:
preference[p] = random.randint(1, 2)
trial = 0
if p == 4 :
print("patient assigned ",p)
while trial <=1:
if noshowtype[p] == 0 & count ==0:
for s in range(SLOT):
if totpat[preference[p]-1, s] == 0:
if availability[p,s] == 1:
assign[p,s,preference[p]-1] = 1
put[p,s] = 1
count = 1
trial = 2
totpat[preference[p]-1,s] = totpat[preference[p]-1,s] + 1
totpatslot[s] = totpatslot[s] + 1
break;
print("patient scheduled ",p)
if count == 0:
for s in range(SLOT):
if totpat[preference[p]-1, s] < slotcap[s]:
if availability[p,s] == 1:
assign[p,s,preference[p]-1] = 1
number_OB[PHY-1] = number_OB[PHY-1] + 1
put[p,s] = 1
count = 1
trial = 2
totpat[preference[p]-1,s] = totpat[preference[p]-1,s] + 1
totpatslot[s] = totpatslot[s] + 1
else:
unschedule[p,s] = unschedule[p,s] + 1
noapp[p] = 1
break;
if noshowtype[p] == 1 & count == 0:
for s in range(SLOT):
if totpat[preference[p]-1, s] == 0:
if availability[p,s] == 1:
assign[p,s,preference[p]-1] = 1
put[p,s] = 1
count = 1
trial = 2
totpat[preference[p]-1,s] = totpat[preference[p]-1,s] + 1
totpatslot[s] = totpatslot[s] + 1
break;
print("patient scheduled ",p)
if count == 0:
for s in range(SLOT):
if totpat[preference[p]-1, s] < slotcap[s]:
if availability[p,s] == 1:
assign[p,s,preference[p]-1] = 1
number_OB[PHY-1] = number_OB[PHY-1] + 1
put[p,s] = 1
count = 1
trial = 2
totpat[preference[p]-1,s] = totpat[preference[p]-1,s] + 1
totpatslot[s] = totpatslot[s] + 1
else:
unschedule[p,s] = unschedule[p,s] + 1
noapp[p] = 1
break;

I'll put it as an answer so that you can understand what I was commenting about.
for p in range(P):
...
trial = 0
while trial <=1:
if ():
for ():
if ():
if ():
...
trial = 2
break;
if ():
for ():
if ():
if ():
...
trial = 2
else:
...
break;
#similarly the other ifs
this is the structure of the code right now, which does not seem simple and is probably redundant at many points. the issue that i was asking you to check was what happens when none of the first indentation if conditions are met? the variable trial will not get updated and you will be stuck in an infinite loop inside while. the only way to break out of this while is too make the variable trial>1 or use a break.
anyways i do not see the point of the while loop here.

Related

how to select a value referring to the last repeated item in a list

I have 5 columns ( NO = index of vehicle / LEADER = index of the vehicle of the front / SEC = instant in seconds / X = position of the vehicle)
Some vehicles stop ( X stay the same for a while) and I want to get the exact time it starts to move again. Then, calculate the difference between their instant and their respective 'leader' vehicle.
I made a code but it has so many bugs
OBS: Some vehicles never stop or stop,but never return to move. I want to remove them too.
Here's my code:
dados = pd.read_excel('teste-reaction_001.xlsx')
n=dados["NO"].unique()
final=np.zeros(1)
for i in n:
botao = 0
array_aux=dados[dados["NO"] == i ]["X"]
df = pd.DataFrame(array_aux)
aux=df.diff().to_numpy()
count1 = 0
aux1 = []
for j in aux:
if j == 0:
botao = 1
elif j != 0 and botao == 1:
aux1=np.where(aux==j)[0]
aux1=aux1[np.where(aux1>=count1)[0]]
break
else :
botao = 0
count1 = count1 + 1
aux2=dados["SEC"][dados[dados["NO"]==i]["SEC"].index[aux1]].values[0]
final=np.append(final,aux2)
tr=np.zeros(1)
for i in n:
aux=dados[dados["NO"] == i ]["LEADER"].unique()[0]
aux1=np.where(dados["NO"].unique()==i)[0]
aux2=np.where(dados["NO"].unique()==aux)[0]
if aux2>-1:
aux3=final[int(aux1)]-final[aux2]
else:
aux3 = "s"
tr=np.append(tr,aux3)
columns = ["N", "TR"]
tabela = np.array([dados["NO"].unique(), tr[1:]])
res = pd.DataFrame(data=tabela.T,index=np.arange(len(tabela.T)), columns=columns)

how do print a data analysis summary table in python?

After testing pokers hands x amount of times, I need to print a table with the title of the hand (full house, flush, etc.), the number of times each of them occurred, the percentage of times they occurred, expected percentage, and difference between the two. It won't let me run it with more than 2 iterations.
Here is what I have:
def is_pair(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if (card['value']) == (i['value']):
count += 1
if count == 2:
Yes = 1
if Yes == 0:
return False
else:
if is_full_house(hand) is True:
return False
elif is_2_pair(hand) is True:
return False
elif is_3_of_a_kind(hand) is True:
return False
elif is_4_of_a_kind(hand) is True:
return False
else:
return True
def is_2_pair(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 2:
Yes += 1
if Yes == 4:
if is_4_of_a_kind(hand) is True:
return False
elif is_full_house(hand) is True:
return False
else:
return True
else:
return False
def is_3_of_a_kind(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 3:
Yes = 1
if Yes == 0:
return False
else:
if is_full_house(hand) is True:
return False
else:
return True
def is_4_of_a_kind(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 4:
Yes = 1
if Yes == 0:
return False
else:
return True
def is_full_house(hand):
Yes = 0
if is_3_of_a_kind(hand) is True:
Yes += 1
else:
return False
if is_pair(hand) is True:
Yes += 1
else:
return False
if Yes == 2:
return True
else:
return False
def is_flush(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['suit'] == i['suit']:
count += 1
if count == 5:
Yes = 1
if Yes == 0:
return False
else:
return True
def is_straight(hand):
list = []
for card in hand:
list.append(card['value'])
list.sort()
if is_pair(hand) is True:
return False
elif is_2_pair(hand) is True:
return False
elif is_3_of_a_kind(hand) is True:
return False
elif is_4_of_a_kind(hand) is True:
return False
elif is_full_house(hand) is True:
return False
elif list[4] - list [0] == 4:
return True
else:
return False
def is_high_card(hand):
if (is_pair(hand) is False) and (is_2_pair(hand) is False) and (is_3_of_a_kind(hand) is False) and (is_4_of_a_kind(hand) is False) and (is_flush(hand) is False) and (is_full_house(hand) is False) and (is_straight(hand) is False) and (is_straight_flush(hand) is False):
return True
else:
return False
def is_straight_flush(hand):
if (is_straight(hand) is True) and (is_flush(hand) is True):
return True
else:
return False
def main():
deck = build_deck()
shuffle(deck)
hand = deck[:5]
return hand
def tests():
hand = main()
if is_straight_flush(hand) is True:
return('Straight flush')
elif is_4_of_a_kind(hand) is True:
return('Four of a kind')
elif is_full_house(hand) is True:
return('Full house')
elif is_flush(hand) is True:
return('Flush')
elif is_straight(hand) is True:
return('Straight')
elif is_3_of_a_kind(hand) is True:
return('Three of a kind')
elif is_2_pair(hand) is True:
return('Two pairs')
elif is_pair(hand) is True:
return('One pair')
elif is_high_card(hand) is True:
return('High card')
def main2():
iterations = int(input("How many hands would you like to test? "))
hands = ['Straight flush', 'Four of a kind', 'Full house', 'Flush', 'Straight', 'Three of a kind', 'Two pair', 'One pair', 'High card']
sf_expected = round(40/2598960*100, 4)
fok_expected = round(624/2598960*100, 4)
fh_expected = round(3744/2598960*100, 4)
f_expected = round(5108/2598960*100, 4)
s_expected = round(10200/2598960*100, 4)
tok_expected = round(54912/2598960*100, 4)
tp_expected = round(123552/2598960*100, 4)
op_expected = round(1098240/2598960*100, 4)
hc_expected = round(1302540/2598960*100, 4)
sf_freq = 0
fok_freq = 0
fh_freq = 0
f_freq = 0
s_freq = 0
tok_freq = 0
tp_freq = 0
op_freq = 0
hc_freq = 0
for i in range(iterations):
tests()
if (tests() == 'Straight flush'):
sf_freq += 1
if (tests() == 'Four of a kind'):
fok_freq += 1
if (tests() == 'Full house'):
fh_freq += 1
if (tests() == 'Flush'):
f_freq += 1
if (tests() == 'Straight'):
s_freq += 1
if (tests() == 'Three of a kind'):
tok_freq += 1
if (tests() == 'Two pair'):
tp_freq += 1
if (tests() == 'One pair'):
op_freq += 1
if (tests() == 'High card'):
hc_freq += 1
occurences = [sf_freq, fok_freq, fh_freq, f_freq, s_freq, tok_freq, tp_freq, op_freq, hc_freq]
expected = [sf_expected, fok_expected, fh_expected, f_expected, s_expected, tok_expected, tp_expected, op_expected, hc_expected]
percent = [sf_freq/iterations * 100, fok_freq/iterations * 100, fh_freq/iterations * 100, f_freq/iterations * 100, s_freq/iterations * 100, tok_freq/iterations * 100, tp_freq/iterations * 100, op_freq/iterations * 100, hc_freq/iterations * 100]
difference = [sf_freq/iterations * 100 - sf_expected, fok_freq/iterations * 100 - fok_expected, fh_freq/iterations * 100 - fh_expected, f_freq/iterations * 100 - f_expected, s_freq/iterations * 100 - s_expected, tok_freq/iterations * 100 - tok_expected, tp_freq/iterations * 100 - tp_expected, op_freq/iterations * 100 - op_expected, hc_freq/iterations * 100 - hc_expected]
print("{:<15} {:<15} {:<15} {:<15} {:>15}".format('Hand', 'Occurences','Percent', 'Expected', 'Difference'))
all = [['Straight flush', sf_freq, sf_freq/iterations * 100, sf_expected, sf_freq/iterations * 100 - sf_expected],
['Four of a kind', fok_freq, fok_freq/iterations * 100, fok_expected, fok_freq/iterations * 100 - fok_expected],
['Full house', fh_freq, fh_freq/iterations * 100, fh_expected, fh_freq/iterations * 100 - fh_expected],
['Flush', f_freq, f_freq/iterations * 100, f_expected, f_freq/iterations * 100 - f_expected],
['Straight', s_freq, s_freq/iterations * 100, s_expected, s_freq/iterations * 100 - s_expected],
['Three of a kind', tok_freq, tok_freq/iterations * 100, tok_expected, tok_freq/iterations * 100 - tok_expected],
['Two pair', tp_freq, tp_freq/iterations * 100, tp_expected, tp_freq/iterations * 100 - tp_expected],
['One pair', op_freq, op_freq/iterations * 100, op_expected, op_freq/iterations * 100 - op_expected],
['High card', hc_freq, hc_freq/iterations * 100, hc_expected, hc_freq/iterations * 100 - hc_expected]]
for list in all:
hands, occurences, percent, expected, difference = list
print("{:<15} {:<15} {:<15} {:<15} {:>15}".format(hands, occurences, percent, expected, difference))
main2()
It's a little unclear why you aren't getting any output, which seems to be the implication of your question. Is your code raising an exception?
It looks to me like the problem is with results. This appears to be a standard Python list (containing a collection of integers). Calling something like results/iterations would normally result in something like TypeError: unsupported operand type(s) for /: 'list' and 'int'.
Lists are not intended to support operations that apply to all their elements, but it's also unclear that's what you intended to achieve with this. Your format string specifies that results/iterations * 100 should be rendered in a space 10 characters wide and centered.
I believe you perhaps wanted to iterate through the individual values of hands, results, and expected, producing a set of rows to form a table. In that case I propose the following in place of your second print statement:
for hand, freq, expectation in zip(hands, results, expected):
percent = 100 * freq / iterations
print(f"{hand:^10}{freq:^10}{percent:^10}{expectation:^10}{percent-expectation:^10}")
I have used the somewhat friendlier f-string formatting, but if you have python <3.6 feel free to revert.
In general, the pandas data analysis library is a good fit for this kind of problem, since you can simply put your data in a pandas DataFrame and print it. However I appreciate that you may want to do this in base Python.
While I'm at it, I fear you have another error. You haven't told us what tests() does, but it looks like instead of calling it once per iteration and processing the result you call it many times.
Let me help you tidy your code and make it more maintainable, fixing this issue in the process.
hands = ['Straight flush', 'Four of a kind', 'Full house', 'Flush', 'Straight', 'Three of a kind', 'Two pair', 'One pair', 'High card']
results = {hand: 0 for hand in hands}
denom = 2598960 / 100
expected = [int(40/denom), int(624/denom), int(3744/denom), int(5108/2598960*100), int(10200/denom), int(54912/denom), int(123552/denom), int(1098240/denom), int(1302540/denom)]
for i in range(iterations):
hand = tests()
results[hand] += 1
By using a dictionary to store the results and using the hand name as the key to look up the result for that hand we improve the code.
You would then use results.values() to retrieve the list of results you had before.
I have also put your repeated code into a variable. If you ever had to change it, you now only have to change it in one place, making mistakes much less likely.

Difference between two similar if loops in Python

I have two codes which should perform the same thing but in the first, I am not getting the result but in the second one I am getting output
if (Method == "EMM" ):
if ((Loan_Obligation/12)+EMI) !=0:
DSCR_Post = EBITDA_EMM/((Loan_Obligation/12)+EMI)
else:
0
elif (Method != "EMM" ):
if ((Loan_Obligation/12)+EMI) !=0:
DSCR_Post = EBITDA/((Loan_Obligation/12)+EMI)
else:
0
and other one is:
if (Method == "EMM"):
DSCR_Post = EBITDA_EMM/((Loan_Obligation/12)+EMI) if ((Loan_Obligation/12)+EMI) !=0 else 0
else:
DSCR_Post = EBITDA/((Loan_Obligation/12)+EMI) if ((Loan_Obligation/12)+EMI) !=0 else 0
print('DSCR_Post:',DSCR_Post)
Can someone help me what is the difference between the two codes
In your first code snippet, you are not assigning the 0 to DSCR_Post as you do in the second. Modify as follows:
if Method == "EMM" :
if (Loan_Obligation / 12) + EMI !=0:
DSCR_Post = EBITDA_EMM / ((Loan_Obligation / 12) + EMI)
else:
DSCR_Post = 0 # the 0 has to be assigned!
else: # you do not need a condition here! It can either be equal or not, no third state possible.
if (Loan_Obligation / 12) + EMI !=0:
DSCR_Post = EBITDA / ((Loan_Obligation / 12) + EMI)
else:
DSCR_Post = 0
print('DSCR_Post:',DSCR_Post)
Which can be simplified to the following:
ebid = EBITDA_EMM if Method == "EMM" else EBITDA
DSCR_Post = 0 # 0 will be overwritten if ...
if (Loan_Obligation / 12) + EMI != 0:
DSCR_Post = ebid / ((Loan_Obligation / 12) + EMI)
print('DSCR_Post:',DSCR_Post)

Simulations in Evolutionary Biology - too many loops?

At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient.
For instance:
if random.random() < mm:
z = numpy.random.choice(pat)
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif maleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = maleadult[z][0]
else:
if random.random() < mut:
if femaleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif femaleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = femaleadult[z][0]
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif maleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = maleadult[z][1]
else:
if random.random() < mut:
if femaleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif femaleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = femaleadult[z][0]
where:
mm - male dispersal,
mf - female dispersal,
mut - mutations,
pat - patch,
maleadult - adult male,
femaleadult - adult female,
malejuv - juvenile male,
femalejuv - juvenile female.
As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary.
Does anyone have any ideas to shorten this and, by consequence, making it more efficient?
Your example does not have any loops but it looks like it could be simplified by one:
if random.random() < mm:
z = numpy.random.choice(pat)
for i in range(2):
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif maleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = maleadult[z][i]
else:
if random.random() < mut:
if femaleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif femaleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = femaleadult[z][i]
It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it:
#!python3
#coding=utf-8
import random
maleadult = [[["male adult"], ["another male adult"], ]]
femaleadult = [[["female adult"], ["another female adult"], ]]
malejuv = [[[["male juv"],["another male juv"]]]]
mut = 0.5
mm = 1.0
x = 0
y = 0
z = 0
def some_logic(a, j):
""" does something """
if random.random() < mut:
if a[z][i] == 0:
j[y][x][i] = 1
elif a[z][i] == 1:
j[y][x][i] = 0
# added!
else:
j[y][x][i] = 0
else:
j[y][x][i] = a[z][i]
if random.random() < mm:
z = 0 #numpy.random.choice(pat)
for i in range(2):
print(i)
if random.random() < 0.5:
some_logic(maleadult, malejuv)
else:
some_logic(femaleadult, malejuv)
print(maleadult)
print(malejuv)
print(femaleadult)

How do I run a binary search for words that start with a certain letter?

I am asked to binary search a list of names and if these names start with a particular letter, for example A, then I am to print that name.
I can complete this task by doing much more simple code such as
for i in list:
if i[0] == "A":
print(i)
but instead I am asked to use a binary search and I'm struggling to understand the process behind it. We are given base code which can output the position a given string. My problem is not knowing what to edit so that I can achieve the desired outcome
name_list = ["Adolphus of Helborne", "Aldric Foxe", "Amanita Maleficant", "Aphra the Vicious", "Arachne the Gruesome", "Astarte Hellebore", "Brutus the Gruesome", "Cain of Avernus"]
def bin_search(list, item):
low_b = 0
up_b = len(list) - 1
found = False
while low_b <= up_b and found == False:
midPos = ((low_b + up_b) // 2)
if list[midPos] < item:
low_b = midPos + 1
elif list[midPos] > item:
up_b = midPos - 1
else:
found = True
if found:
print("The name is at positon " + str(midPos))
return midPos
else:
print("The name was not in the list.")
Desired outcome
bin_search(name_list,"A")
Prints all the names starting with A (Adolphus of HelBorne, Aldric Foxe .... etc)
EDIT:
I was just doing some guess and check and found out how to do it. This is the solution code
def bin_search(list, item):
low_b = 0
up_b = len(list) - 1
true_list = []
count = 100
while low_b <= up_b and count > 0:
midPos = ((low_b + up_b) // 2)
if list[midPos][0] == item:
true_list.append(list[midPos])
list.remove(list[midPos])
count -= 1
elif list[midPos] < item:
low_b = midPos + 1
count -= 1
else:
up_b = midPos - 1
count -= 1
print(true_list)
Not too sure if this is what you want as it seems inefficient... as you mention it seems a lot more intuitive to just iterate over the entire list but using binary search i found here i have:
def binary_search(seq, t):
min = 0
max = len(seq) - 1
while True:
if max < min:
return -1
m = (min + max) // 2
if seq[m][0] < t:
min = m + 1
elif seq[m][0] > t:
max = m - 1
else:
return m
index=0
while True:
index=binary_search(name_list,"A")
if index!=-1:
print(name_list[index])
else:
break
del name_list[index]
Output i get:
Aphra the Vicious
Arachne the Gruesome
Amanita Maleficant
Astarte Hellebore
Aldric Foxe
Adolphus of Helborne
You just need to found one item starting with the letter, then you need to identify the range. This approach should be fast and memory efficient.
def binary_search(list,item):
low_b = 0
up_b = len(list) - 1
found = False
midPos = ((low_b + up_b) // 2)
if list[low_b][0]==item:
midPos=low_b
found=True
elif list[up_b][0]==item:
midPos = up_b
found=True
while True:
if found:
break;
if list[low_b][0]>item:
break
if list[up_b][0]<item:
break
if up_b<low_b:
break;
midPos = ((low_b + up_b) // 2)
if list[midPos][0] < item:
low_b = midPos + 1
elif list[midPos] > item:
up_b = midPos - 1
else:
found = True
break
if found:
while True:
if midPos>0:
if list[midPos][0]==item:
midPos=midPos-1
continue
break;
while True:
if midPos<len(list):
if list[midPos][0]==item:
print list[midPos]
midPos=midPos+1
continue
break
else:
print("The name was not in the list.")
the output is
>>> binary_search(name_list,"A")
Adolphus of Helborne
Aldric Foxe
Amanita Maleficant
Aphra the Vicious
Arachne the Gruesome
Astarte Hellebore

Categories

Resources