Related
I have a numpy array with shape (140, 23, 2) being 140 frames, 23 objects, and x,y locations. The data has been generated by a GAN and when I animate the movement it's very jittery. I want to smooth it by converting the coordinates for each object so every odd number index to be the mid-point between the even numbered indices either side of it. e.g.
x[1] = (x[0] + x[2]) / 2
x[3] = (x[2] + x[4]) / 2
Below is my code:
def smooth_coordinates(df):
# df shape is (140, 23, 2)
# iterate through each object (23)
for j in range(len(df[0])):
# iterate through 140 frames
for i in range(len(df)):
# if it's an even number and index allows at least 1 index after it
if (i%2 != 0) and (i < (len(df[0])-2)):
df[i][j][0] = ( (df[i-1][j][0]+df[i+1][j][0]) /2 )
df[i][j][1] = ( (df[i-1][j][1]+df[i+1][j][1]) /2 )
return df
Aside from it being very inefficient my input df and output df are identical. Any suggestions for how to achieve this more efficiently?
import numpy as np
a = np.random.randint(100, size= [140, 23, 2]) # input array
b = a.copy()
i = np.ogrid[1: a.shape[0]-1: 2] # odd indicies
i
>>> [ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25,
27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51,
53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77,
79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103,
105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129,
131, 133, 135, 137]
(a == b).all() # testing for equality
>>> True
a[i] = (a[i-1] + a[i+1]) / 2 # averaging positions across frames
(a == b).all() # testing for equality again
>>> False
I replace in this code
import matplotlib.pyplot as plt
#parametry dla romeo i julii, zeby byly niezmienne w uczuciach musza byc wieksze od 0
aR = 0.5
aL = 0.7
#pR pL odpowiedzi Romea/Julii na miłość
pR = 0.2
pL = 0.5
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
rom = []
jul = []
def Romeo(n):
if n == 0:
return 1
return Romeo(n - 1)*aR
def Julia(n):
if n == 0:
return 1
return Julia(n - 1)*aL
def alfa(n):
if n == 0:
return 1
return aR*Romeo(n - 1) + pR*Julia(n - 1)
def beta(n):
if n == 0:
return 1
return aL*Julia(n - 1) + pL*Romeo(n - 1)
j = 0
while j < 100:
rom.append(alfa(j))
j+=1
j = 0
while j < 100:
jul.append(beta(j))
j+=1
plt.plot(x, rom, label = "Romeo love")
plt.plot(x, jul, label = "Julia love")
plt.xlabel("Days")
plt.ylabel("Romeo love")
plt.title("Some graph")
plt.legend()
plt.show()
only alfa and beta functions byt this:
import matplotlib.pyplot as plt
#parametry dla romeo i julii, zeby byly niezmienne w uczuciach musza byc wieksze od 0
aR = 0.5
aL = 0.7
#pR pL odpowiedzi Romea/Julii na miłość
pR = 0.2
pL = 0.5
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, ]
rom = []
jul = []
def Romeo(n):
if n == 0:
return 1
return Romeo(n - 1)*aR
def Julia(n):
if n == 0:
return 1
return Julia(n - 1)*aL
def alfa(n):
if n == 0:
return 1
return round(aR*alfa(n - 1) + pR*beta(n - 1), 3)
def beta(n):
if n == 0:
return 1
return round(aL*beta(n-1) + pL*alfa(n - 1), 3)
j = 0
while j < 100:
rom.append(alfa(j))
j+=1
j = 0
while j < 100:
jul.append(beta(j))
j+=1
plt.plot(x, rom, label = "Romeo love")
plt.plot(x, jul, label = "Julia love")
plt.xlabel("Days")
plt.ylabel("Romeo love")
plt.title("Some graph")
plt.legend()
plt.show()
And Pycharm does not want to compilate (does not draw this graph) or it will take a lot of time. Ealier it was not a problem. \
I thought that a lot of numbers after point can be a reason and i round every number from list, but it didnt solve the problem.
What I changed by replacing this functions? How can I fix that?
Im pretty sure that the problem is in assigning elements from functions to list [2 while]. But i do not know why.
The current recursive approach is wasteful.
For example, when computing alfa(1) would require alfa(0), beta(0).
When you move on to alfa(2), the code will first compute alfa(1) and beta(1). Then alfa(1) would call alfa(0) and beta(0), while beta(1) would separately call alfa(0), beta(0) again, without recycling what we have computed before. So you need 6 calls for alfa(2).
At alfa(3), you would compute alfa(2) and beta(2), each of which needs 6 calls; so you need 14 calls (if my math is not off).
Imagine how many computations you would need at n == 100; the answer is 2535301200456458802993406410750. Cumulatively, i.e., since you want to plot alfa(1), ..., alfa(100), you need 5070602400912917605986812821300
computations in total, only to produce a single list rom.
You can use memoization to remember the previously calculated results and recycle them.
In python, you can achieve this by using functools.lru_cache (python doc); put
from functools import lru_cache
at the beginning of your code and then put
#lru_cache()
before each function; e.g.,
#lru_cache()
def Romeo(n):
if n == 0:
return 1
return Romeo(n - 1)*aR
You will see the graph almost immediately now.
New to Jupyter Notebook, computing this code to return sum of values that are a multiple of 3 and 5, AND less than 100 in my list range 1, 100. I've got a feeling that I'm truncating the code by removing 3 and 5 from the equation. Not sure how/where to include that.
print(list(range(1, 100)))
multiple35 = 0
for i in range (1, 100):
if i % 15 == 0 and multiple35 <= 100:
multiple35 += i
print(multiple35)
My print line returns the range, Plus the 3 correct multiples less than 100. BUT ALSO prints 150, which is greater than and should be excluded from the result.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
15
45
90
150
Appreciate your help here.
BUT ALSO prints 150, which is greater than and should be excluded from the result.
The reason is simple. You are testing multiple35 <= 100 before the addition (multiple35 += i). So the sum is printed first and then tested in the next round. Therefore the output ends after the first occurrence that is bigger than 100.
By the way, it is useless to go through all natural numbers and only do anything on each 15th element (because of i % 15 == 0). You can use a tailored range instead:
>>> list(range(15,100,15))
[15, 30, 45, 60, 75, 90]
So a simplified loop which would stop printing when reaching 100, could look like:
multiple35 = 0
for i in range (15, 100, 15):
multiple35 += i
if multiple35 > 100:
break # no reason to continue the loop, the sum will never go back below 100
print(multiple35)
You have to check if the final target will exceed the threshold, because in your loop, when i=75, it satisfies the condition 75%15==0 and also satisfies 75<=100 and since it satisfies both, we let it into the next block which adds 75 to it and gives 150 which exceeds the threshold. The solution is to not even allow a number inside the adding part if when added, crosses the threshold,
There are simpler solutions like above by #Melebius but, I wanted to explain this in the way OP has written
multiple35 = 0
for i in range (1, 100):
if i % 15 == 0 and multiple35+i<=100:
multiple35 += i
print(multiple35)
There are multiple flaws in your logic. I am not going to address them all, but instead suggest an alternate way to solve your issue.
Simply notice that multiples of 3 and 5 are exactly the multiples of 15. So there is no need to range over all numbers from 0 to 100.
for x in range(15, 100, 15):
print(x)
# 15
# 30
# 45
# 60
# 75
# 90
You also mention that you want to sum all numbers. In python, you can sum over any iterator with sum, including a range.
print(sum(range(15, 100, 15)))
# 315
You can use list comprehension also here
values = [i for i in range(1,100) if i%5==0 if i%3==0]
print("Numbers divisible by 3 and 5:",values)
sum_of_numbers = 0
for i,items in enumerate(values):
sum_of_numbers = sum_of_numbers+items
if sum_of_numbers>100:
break
print(values[:i])
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
There is height list it's total 1743 cm. I have 6 cells I want to put this numbers in cells. Max height is 300 cm. I use for loop for it it will take numbers inside height list and plus them until get closer 300 cm
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
max_height=300 #cm
sum1=0
count=0
for i in height:
sum1=height[count]+sum1
count+=1
if max_height>=sum1>=250:
print(sum1)
sum1=0
print(sum1)
print("\n",sum(height))
I expected it will get 6 sum but get 7 sum.
if you run you will see (254,289,273,261,289,292,85)
It is not full solution but i hope it can help you, main idea is find most nearest value to generate summ 300
height = [67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
elems = [height.pop(0)]
groups = []
while height:
while sum(elems) <= 300:
next_el = 0
for elem in height:
if sum(elems) + elem <= 300 and elem > next_el:
next_el = elem
if next_el:
elems.append(height.pop(height.index(next_el)))
else:
print(sum(elems))
print(elems)
groups.append(elems)
elems = []
break
print('Total: ', sum([sum(x) for x in groups]))
my result is:
273
[67, 74, 67, 65]
300
[65, 65, 65, 65, 40]
300
[65, 64, 63, 61, 47]
297
[61, 61, 59, 58, 58]
281
[58, 58, 57, 55, 53]
292
[51, 46, 45, 43, 40, 39, 28]
Total: 1743
The problem you are trying to solve is computationally complex. It looks like a variant of the Knapsack problem. This is a greedy approach, but it is fairly fast. Because it's greedy it is possible that it may fail to find a solution if one exists.
eg. [120, 120, 100, 80, 65, 65] with max height of 300 has a minimal solution of [[120, 100, 80], [120, 65, 65]], but this algorithm fails to find it, and instead returns [[120, 120], [100, 80, 65], [65]]
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45,
65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
max_height=300 #cm
heights = sorted(height, reverse=True)
groups = []
while heights:
# whilst there are still items in heights, create a new group of heights
# with sum no more than 300.
group = []
# greedily fill up each group with largest possible values that can fit
for h in heights:
if sum(group) + h <= 300:
group.append(h)
# remove the values in the group from the list of candidate heights
for g in group:
heights.remove(g)
groups.append(tuple(group))
# output
for g in groups:
print(g, '->', sum(g))
gives:
(74, 67, 67, 65) -> 273
(65, 65, 65, 65, 40) -> 300
(65, 64, 63, 61, 47) -> 300
(61, 61, 59, 58, 58) -> 297
(58, 58, 57, 55, 53) -> 281
(51, 46, 45, 43, 40, 39, 28) -> 292
Note that the first group it found is actually the worst in terms of how close to the limit it is. This goes back to the initial point about this algorithm being greedy and not always finding the solution with the minimum number of groups.
This is an algorithmic problem.
The gotcha here seems to be that if you fill up one cell at a time then your values that may not fit in the latest cell may still fit in a previous cell. So you are not taking full advantage of each cell's size, for example, your first cell contains just 254 which means you can fit a whole extra 46 cms in there (which appears later in your list).
To solve it you need to actually create a representation for the cells (a list and/or counter, although you can always create a sum of the list...), and revisit cells to check if more data fits.
you need to find the combinations that are 6 elements long, and then you want to get is as close to 300 as possible
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
valid_combs = []
import itertools
for comb in itertools.combinations(height, 6):
#if sum(comb) <= 300 and sum(comb) >+ 290:
if sum(comb) == 300:
valid_combs.append(comb)
print(comb)
this will extract valid 6 length combinations from the set, and then check if it sums to 300. the commented out condition above it is if you want to have it within a range, such as 290 to 300 etc
you can modify the condition as necessary, such as if sum(comb) >= 250
I may have misunderstood the problem initially. But reconsidering the input, your goal is to group the data such that the sum of an unspecified length does not exceed some threshold. Using numpy this may be a good place to start:
edit: this assumes the order of the data needs to preserved, otherwise I would use a quantile based approach.
edit2: without order preservation
import numpy as np
height = np.array(\
[67, 67, 55, 65, 65, 65, 61, 58, 40, 40,\
58, 53, 59, 63, 51, 57, 43, 65, 45, 65,\
61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39])
height.sort()
threshold = 300
groupings = np.where(np.diff(height.cumsum() // threshold))[0]
ends = np.hstack((groupings, height.size))
starts = np.roll(ends.copy(), 1) + 1
starts[0] = 0
for start, end in zip(starts, ends):
print(f'Grouping: {height[start:end]} sum: {height[start:end].sum()}')
Output:
Grouping: [28 39 40 40 43 45] sum: 235
Grouping: [47 51 53 55] sum: 206
Grouping: [58 58 58 58 59] sum: 291
Grouping: [61 61 63] sum: 185
Grouping: [65 65 65 65] sum: 260
Grouping: [65 67 67 74] sum: 273
My approach is to find and use combinations that fill cells with exactly 300 total height. It is not optimal.
import itertools
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
def fill_cell(cells, comb):
cells.append(comb) #fill cell
for h in comb:
del height[height.index(h)] #delete elemets from heights array
cells = []
When first required combination is found - I fill_cell and delete used elements from height array.
As we don't have number of items per cell restriction - I will vary this number.
In this case there is combination of 7 items with total height sum - 300:
for comb in itertools.combinations(height, 7):
if sum(comb) == 300:
print(comb) #(55, 40, 40, 53, 45, 28, 39)
fill_cell(cells,comb)
print(len(height)) #24
break
After that I found few more combinations of 5 item and with 300 total height.
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb) #(67, 67, 65, 58, 43)
fill_cell(cells,comb)
print(len(height)) #19
break
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb)
fill_cell(cells,comb) #(65, 65, 61, 58, 51)
print(len(height)) #14
break
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb)
fill_cell(cells,comb) #(59, 63, 57, 47, 74)
print(len(height)) # 9
break
At this point I have 4 cells with directly 300 total height.
I didn't find more combinations with directly 300 total height.
I decided to manually define remaining cells:
print(cells)
print(height)
fill_cell(cells,height[:4])
fill_cell(cells,height[:])
print("Result:")
for c in cells:
print(sum(c), c)
print("Total height: ", sum([sum(c) for c in cells]))
Finally:
Result:
300 (55, 40, 40, 53, 45, 28, 39)
300 (67, 67, 65, 58, 43)
300 (65, 65, 61, 58, 51)
300 (59, 63, 57, 47, 74)
249 [65, 65, 61, 58]
294 [58, 65, 64, 61, 46]
Total height: 1743
Update:
Following code do the same. It iteratively changes combination parameters and reduces height limit if combination with 300 height didn't found:
import itertools
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
def fill_cell(cells, comb):
cells.append(comb) #fill cell
for h in comb:
del height[height.index(h)] #delete elemets from heights array
cells = []
max_height = 300
max_elements = 7
elements = max_elements
cell_filled = True
while height:
if cell_filled == False:
elements-=1
if elements==0:
elements = max_elements
max_height-=1
for comb in itertools.combinations(height, min(elements,len(height))):
if sum(comb) == max_height:
print(comb)
fill_cell(cells, comb)
print(len(height))
cell_filled = True
break
cell_filled = False
print("Result:")
for c in cells:
print(sum(c), c)
print("Total height: ", sum([sum(c) for c in cells]))
I have made a piece of code that spits out prime numbers up to the 10001st number. It currently takes up 4 lines of code, and was wondering if I could condense it further? Here it is;
for i in range(3,104744,2):
for x in range(3,int(i/2),2):
if i % x == 0 and i != x: break
else: print(i)
I am aware that condensing code too much is usually not a good thing, but was wondering if it was possible.
Thanks.
You can use a list comprehension and any to get a one-liner solution:
>>> [p for p in range(2, 100) if not any (p % d == 0 for d in range(2, int(p**0.5) + 1))]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
It uses the fact that a divisor cannot be larger than the square root of the number it divies.
It seems to work fine:
>>> len([p for p in range(2, 104744) if not any (p % d == 0 for d in range(2,int(p**0.5)+1))])
10001
List comprehension
>>> r=range(2,100)
>>> [p for p in r if [p%d for d in r].count(0)<2]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Try this one:
for i in range(3,100,2):
if all( i%x for x in range(3, i//2, 2) ):
print(i)