How to run a calculation until true within a loop python - python

Hi so a quick question for spyder python 3.6
Say I have a simple while loop or if statement.
import random
from decimal import Decimal
usraccbal = (1000.01)
def rate():
ratecontents = (random.random() * (1.202 - 0.308) + 0.308)
return ratecontents
def newconvert(amount, rate):
a = (amount * rate)
return a, amount
b = rate()
rate1 = b
c = newconvert(usraccbal, rate1)
newcnvrt = (c[0])
prevusraccbal = (c[1])
#while or if here
if newcnvrt == prevusraccbal or newcnvrt < prevusraccbal:
#Continue calculating until newcnvrt > prevusraccbal
#then update values
else:
#Update values
usraccbal = newcnvrt
As you can see I would like to continue trying to get a newcnvrt which equals more than prevusraccbal either in an if or a while loop. So importantly it is constantly getting a new exchange rate and trying to use that.
The code is actually in a function normally which has root.after(3000,results) and is actioned by a button press

You should be able to replace .... < .... or .... == .... with .... <= .....
Just add a while with your condition. It executes until the condition is no longer True, and then the loop exits.
while newcnvrt <= prevusraccbal:
... # calculate until condition is false
usraccbal = newcnvrt

Related

How can I optimize the groupby.apply(function) in Python?

I have a function that uses deque.collections to track daily stock in based on FIFO. An order will be fulfilled if possible and is substracted from stock accordingly. I use a function in groupby.apply(my_function).
I have struggles where to place the second loop. Both loops work properly when run on their own. But I do not get them working combined.
The dataset is about 1.5 million rows.
Thanks.
DOS = 7
WIP = 1
df_fin['list_stock'] = 0
df_fin['stock_new'] = 0
def create_stocklist(x):
x['date_diff'] = x['dates'] - x['dates'].shift()
x['date_diff'] = x['date_diff'].fillna(0)
x['date_diff'] = (x['date_diff'] / np.timedelta64(1, 'D')).astype(int)
x['list_stock'] = x['list_stock'].astype(object)
x['stock_new'] = x['stock_new'].astype(object)
var_stock = DOS*[0]
sl = deque([0],maxlen=DOS)
for i in x.index:
order = x['order_bin'][i]
if x['date_diff'][i] > 0:
for p in range(0,x['date_diff'][i]):
if p == WIP:
sl.appendleft(x.return_bin[i-1])
else:
sl.appendleft(0)
sl_list = list(sl)
sl_list.reverse()
new_list = []
#from here the loop does not work as I wanted it to work.
#I want to loop over de created sl_list
#and then start the loop above with the outcome of the loop below.
for elem in sl_list:
while order > 0:
val = max(0,elem-order)
order = (abs(min(0,elem-order)))
new_list.append(val)
break
else:
new_list.append(elem)
new_list.reverse()
x.at[i,'list_stock'] = new_list
sl = deque(new_list)
return x
df_fin.groupby(by=['ID']).apply(create_stocklist)
You do not have access to sl_list inside the second loop, you should just define it in the upper scope: for example just after the first global for loop:
for i in x.index:
# define it just here
sl_list = []
order = x['order_bin'][i]

How can I structure this while loop so that it checks for two conditions and also termaintes it when necessary

I have this code here
def step(self, joint_values):
"""
Step function which publishes actions and evaluates state/reward.
Args:
action: takes an action (Int) as input. Value from 0-6
Returns:
State after executed action, reward after executed action and done,
which is a bool, True or False depending on if episode is done.
"""
self.iterator += 1
self._coll = self.observation_callback_collision()
coll_force = self._coll.wrench.force.x
if coll_force >= 150 or coll_force <= -150:
self.reset_robot2.call()
self.reward_coll = -0.5
self.collided += 1
print("#############Collision##############")
rospy.sleep(1)
#print("ACTION", joint_values)
else:
i = 0
while i<=1000:
self.traj.header.stamp = rospy.Time.now()
action = JointTrajectoryPoint()
action.positions = joint_values
#print("W", action.positions)
action.time_from_start = rospy.Duration(0.7)
self.traj.points = []
self.traj.points.append(action)
#rospy.sleep(4.5)
self.action_pub.publish(self.traj)
i +=0.1
If you see here what I am trying to achieve is, whenever the step function is called it checks for the if condition (if it is true then it resets the robot or else it activates the while loop). The problem is when RL agent chooses a action "joint_values" such that when the step function is called, the if con
is checked only once and if the action chosen by the agent is not good the robot goes in collision.
what I want is that when the step function is called the while loop while i<= 1000 which terminates at i += 1, also checks every time for the collision i.e. coll_force >= 150 or coll_force <= -150: and if the collision exceeds the limits it stops publishing the action (self.action_pub.publish(self.traj)) and resets the robot (self.reset_robot2.call()).
I know its bit confusing but what I am trying to do is something like this,
def step(self, joint_values):
self.iterator += 1
self._coll = self.observation_callback_collision()
coll_force = self._coll.wrench.force.x
while i<=1000:
if coll_force >= 150 or coll_force <= -150:
self.reset_robot2.call()
self.reward_coll = -0.5
self.collided += 1
print("#############Collision##############")
rospy.sleep(1)
else:
self.traj.header.stamp = rospy.Time.now()
action = JointTrajectoryPoint()
action.positions = joint_values
#print("W", action.positions)
action.time_from_start = rospy.Duration(0.7)
self.traj.points = []
self.traj.points.append(action)
self.action_pub.publish(self.traj)
i +=0.1
But this here doesn't seem to work properly
Generally when you want to check for multiple conditions in a loop, you can use an accumulated flag that indicates if the loop should terminate. There are other options, such as break or setting i to a value outside the range, but for readability it might be best to use the flag:
is_running = True
while is_running:
# do stuff here, calculate coll_force
i += 0.1
is_running = is_running and (coll_force > -150 and coll_force < 150)
is_running = is_running and i <= 1000
This way you can use as many conditions as you like, each conditions can be handled seperately from the others and you have an obvious place where you can read the code that checks the conditions, namely at the end of the loop block.
I like Etienne's answer. And would advise you to structure your function as he suggests. Alternatively, here is a modification to your first attempt that should do exactly what you want it to do.
I added a reset_one state that acts as a second condition to be met by your if statement. If the if has been called once, it will be set to true and will disallow the if catch, only allowing the else to be called.
Alternatively you can use the reset_count variable I have commented out if you allow a certain amount of resets.
def step(self, joint_values):
self.iterator += 1
self._coll = self.observation_callback_collision()
coll_force = self._coll.wrench.force.x
# Add has_been_reset boolean state.
reset_once = False
# reset_count = 0 # Alternative.
while i <= 1000:
# Added second condition. Modify condition if you allow a certain
# amount of resets during the while loop. Here it allows the if
# condition to be triggered ONCE (Use reset_count <= n_allowed
# alternatively)
if (coll_force >= 150 or coll_force <= -150) and not reset_once:
self.reset_robot2.call()
self.reward_coll = -0.5
self.collided += 1
print("#############Collision##############")
rospy.sleep(1)
reset_once = True # <--------------
# reset_count += 1 # <-- Alternative
else:
self.traj.header.stamp = rospy.Time.now()
action = JointTrajectoryPoint()
action.positions = joint_values
# print("W", action.positions)
action.time_from_start = rospy.Duration(0.7)
self.traj.points = []
self.traj.points.append(action)
self.action_pub.publish(self.traj)
i += 0.1
Edit: Typo*

Calculating times in a range

I am trying to learn Python and I am stuck in a date/time routine I need to find data that occurred between 05:00 and 11:30, but no matter how I go about this I get an error. I would think that I need decode the time, do the math and then encode the time. I am sure it is a simple thing to do but I cannot seem to get it done.
Example:
riders = [
["rider_2391", 37_775370, -122.417571, 37_808601, -122.409807, "17:02:35", "$17.23", "UberX"],
["rider_1879", 37.775222, 122.47109, 37.808080, -122.410002, "06:25:08", "$22.25", "UberX"],
["rider_98233", 37.784125, -122.471891, 37.763025, 122.478749, "11:48:55", "$6.28", "Pool"]
]
def getRiderDate(riders):
ans = []
for rider in riders:
if rider[5] >= "05:00:00" and rider[5] <= "11:30:00":
ans.insert(len(ans), rider)
return ans
print(getRiderDate(riders)
Your problem is faulty loop control:
for rider in riders:
if rider[5] >= "05:00:00" and rider[5] <= "11:30:00":
ans.insert(len(ans), rider)
return ans;
You check one rider and return, regardless off the match. Try this:
def getRiderDate(riders):
ans = []
for rider in riders:
if rider[5] >= "05:00:00" and rider[5] <= "11:30:00":
ans.append(rider)
return ans;
return goes after the loop, not inside.
Output:
[['rider_1879', 37.775222, 122.47109, 37.80808, -122.410002, '06:25:08', '$22.25', 'UberX']]
I would use datetime module, mainly time. Also what previous answers are pointing out (return of ans inside of the loop, etc.)
import datetime
riders = [["rider_2391", 37_775370, -122.417571, 37_808601, -122_409807, "17:02:35", "$17.23", "UberX"],
["rider_1879", 37.775222, 122.47109, 37.808080, -122.410002, "06:25:08", "$22.25", "UberX"],
["rider_98233", 37.784125, -122.471891, 37.763025, 122.478749, "11:48:55", "$6.28", "Pool"]]
def getRiderDate(riders):
ans = []
t1 = datetime.time(hour=5)
t2 = datetime.time(hour=11, minute=30)
for rider in riders:
t = datetime.datetime.strptime(rider[5], '%H:%M:%S').time()
if t1 <= t <= t2: # using chained comparison
ans.insert(len(ans), rider)
return ans
print(getRiderDate(riders))

Python Filtering a Point Cloud with PhotoScan Based on a Threshold Value - basic python help needed

I'm trying to implement a filter with Python to sort out the points on a point cloud generated by Agisoft PhotoScan. PhotoScan is a photogrammetry software developed to be user friendly but also allows to use Python commands through an API.
Bellow is my code so far and I'm pretty sure there is better way to write it as I'm missing something. The code runs inside PhotoScan.
Objective:
Selecting and removing 10% of points at a time with error within defined range of 50 to 10. Also removing any points within error range less than 10% of the total, when the initial steps of selecting and removing 10% at a time are done. Immediately after every point removal an optimization procedure should be done. It should stop when no points are selectable or when selectable points counts as less than 1% of the present total points and it is not worth removing them.
Draw it for better understanding:
Actual Code Under Construction (3 updates - see bellow for details):
import PhotoScan as PS
import math
doc = PS.app.document
chunk = doc.chunk
# using float with range and that by setting i = 1 it steps 0.1 at a time
def precrange(a, b, i):
if a < b:
p = 10**i
sr = a*p
er = (b*p) + 1
p = float(p)
for n in range(sr, er):
x = n/p
yield x
else:
p = 10**i
sr = b*p
er = (a*p) + 1
p = float(p)
for n in range(sr, er):
x = n/p
yield x
"""
Determine if x is close to y:
x relates to nselected variable
y to p10 variable
math.isclose() Return True if the values a and b are close to each other and
False otherwise
var is the tolerance here setted as a relative tolerance:
rel_tol is the relative tolerance – it is the maximum allowed difference
between a and b, relative to the larger absolute value of a or b. For example,
to set a tolerance of 5%, pass rel_tol=0.05. The default tolerance is 1e-09,
which assures that the two values are the same within about 9 decimal digits.
rel_tol must be greater than zero.
"""
def test_isclose(x, y, var):
if math.isclose(x, y, rel_tol=var): # if variables are close return True
return True
else:
False
# 1. define filter limits
f_ReconstUncert = precrange(50, 10, 1)
# 2. count initial point number
tiePoints_0 = len(chunk.point_cloud.points) # storing info for later
# 3. call Filter() and init it
f = PS.PointCloud.Filter()
f.init(chunk, criterion=PS.PointCloud.Filter.ReconstructionUncertainty)
a = 0
"""
Way to restart for loop!
should_restart = True
while should_restart:
should_restart = False
for i in xrange(10):
print i
if i == 5:
should_restart = True
break
"""
restartLoop = True
while restartLoop:
restartLoop = False
for count, i in enumerate(f_ReconstUncert): # for each threshold value
# count points for every i
tiePoints = len(chunk.point_cloud.points)
p10 = int(round((10 / 100) * tiePoints, 0)) # 10% of the total
f.selectPoints(i) # selects points
nselected = len([p for p in chunk.point_cloud.points if p.selected])
percent = round(nselected * 100 / tiePoints, 2)
if nselected == 0:
print("For threshold {} there´s no selectable points".format(i))
break
elif test_isclose(nselected, p10, 0.1):
a += 1
print("Threshold found in iteration: ", count)
print("----------------------------------------------")
print("# {} Removing points from cloud ".format(a))
print("----------------------------------------------")
print("# {}. Reconstruction Uncerntainty:"
" {:.2f}".format(a, i))
print("{} - {}"
" ({:.1f} %)\n".format(tiePoints,
nselected, percent))
f.removePoints(i) # removes points
# optimization procedure needed to refine cameras positions
print("--------------Optimizing cameras-------------\n")
chunk.optimizeCameras(fit_f=True, fit_cx=True,
fit_cy=True, fit_b1=False,
fit_b2=False, fit_k1=True,
fit_k2=True, fit_k3=True,
fit_k4=False, fit_p1=True,
fit_p2=True, fit_p3=False,
fit_p4=False, adaptive_fitting=False)
# count again number of points in point cloud
tiePoints = len(chunk.point_cloud.points)
print("= {} remaining points after"
" {} removal".format(tiePoints, a))
# reassigning variable to get new 10% of remaining points
p10 = int(round((10 / 100) * tiePoints, 0))
percent = round(nselected * 100 / tiePoints, 2)
print("----------------------------------------------\n\n")
# restart loop to investigate from range start
restartLoop = True
break
else:
f.resetSelection()
continue # continue to next i
else:
f.resetSelection()
print("for loop didnt work out")
print("{} iterations done!".format(count))
tiePoints = len(chunk.point_cloud.points)
print("Tiepoints 0: ", tiePoints_0)
print("Tiepoints 1: ", tiePoints)
Problems:
A. Currently I'm stuck on an endless processing because of a loop. I know it's about my bad coding. But how do I implement my objective and get away with the infinite loops? ANSWER: Got the code less confusing and updated above.
B. How do I start over (or restart) my search for valid threshold values in the range(50, 20) after finding one of them? ANSWER: Stack Exchange: how to restart a for loop
C. How do I turn the code more pythonic?
IMPORTANT UPDATE 1: altered above
Using a better range with float solution adapted from stackoverflow: how-to-use-a-decimal-range-step-value
# using float with range and that by setting i = 1 it steps 0.1 at a time
def precrange(a, b, i):
if a < b:
p = 10**i
sr = a*p
er = (b*p) + 1
p = float(p)
return map(lambda x: x/p, range(sr, er))
else:
p = 10**i
sr = b*p
er = (a*p) + 1
p = float(p)
return map(lambda x: x/p, range(sr, er))
# some code
f_ReconstUncert = precrange(50, 20, 1)
And also using math.isclose() to determine if selected points are close to the 10% selected points instead of using a manual solution through assigning new variables. This was implemented as follows:
"""
Determine if x is close to y:
x relates to nselected variable
y to p10 variable
math.isclose() Return True if the values a and b are close to each other and
False otherwise
var is the tolerance here setted as a relative tolerance:
rel_tol is the relative tolerance – it is the maximum allowed difference
between a and b, relative to the larger absolute value of a or b. For example,
to set a tolerance of 5%, pass rel_tol=0.05. The default tolerance is 1e-09,
which assures that the two values are the same within about 9 decimal digits.
rel_tol must be greater than zero.
"""
def test_threshold(x, y, var):
if math.isclose(x, y, rel_tol=var): # if variables are close return True
return True
else:
False
# some code
if test_threshold(nselected, p10, 0.1):
# if true then a valid threshold is found
# some code
UPDATE 2: altered on code under construction
Minor fixes and got to restart de for loop from beginning by following guidance from another Stack Exchange post on the subject. Have to improve the range now or alter the isclose() to get more values.
restartLoop = True
while restartLoop:
restartLoop = False
for i in range(0, 10):
if condition:
restartLoop = True
break
UPDATE 3: Code structure to achieve listed objectives:
threshold = range(0, 11, 1)
listx = []
for i in threshold:
listx.append(i)
restart = 0
restartLoop = True
while restartLoop:
restartLoop = False
for idx, i in enumerate(listx):
print("do something as printing i:", i)
if i > 5: # if this condition restart loop
print("found value for condition: ", i)
del listx[idx]
restartLoop = True
print("RESTARTING LOOP\n")
restart += 1
break # break inner while and restart for loop
else:
# continue if the inner loop wasn't broken
continue
else:
continue
print("restart - outer while", restart)

variable within a nested loop in python

I'm trying to figure what the values of xcoord_orig and ycoord_orig are when the last conditional statement is true i.e. when board[xcoordT][ycoordT] == computer. I feel that as I have it right now, I'm simply printing their values if the conditional statement is true. But what I really want are the values of xcoord_orig and ycoord_orig under the first loop at the point where the last conditional statement is true. I'm not sure if this is clear but I thought I would ask.
for num in range(8):
for i in range(len(valid_list)):
xcoord_orig = valid_list[i][0]
ycoord_orig = valid_list[i][1]
xcoord1 = valid_list[i][0] + num_list[num]
ycoord1 = valid_list[i][1] + num_list2[num]
if 0 <= xcoord1 <= 7 and 0 <= ycoord1 <= 7:
piece = board[xcoord1][ycoord1]
if piece == player:
move_list = []
for i in range(2,8):
xcoordT = xcoord_orig
ycoordT = ycoord_orig - i
print(xcoord_orig, ycoord_orig)
if board[xcoordT][ycoordT] == computer:
move_list.append([xcoordT, ycoordT])
print(xcoord_orig, ycoord_orig)
This
for i in range(len(valid_list)):
...
for i in range(2,8):
Is epic fail. It can't be correct.

Categories