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.
I'm a novice in Python and my homework is to take a list with a bunch of numbers in it and
make the list ordered from lowest number to highest
get rid of duplicate numbers.
This must be accomplished with loops
My code so far:
numbers = [84, 79, 66, 69, 79, 82, 78, 79, 84, 84, 79, 66, 69, 84,
72, 65, 84, 73, 83, 84, 72, 69, 81, 85, 69, 83, 84, 73, 79, 78]
ordered = []
while numbers != []:
min = numbers[0]
for i in range(0, len(numbers)):
if numbers[i] < min:
min = numbers[i]
ordered.append(min)
j = 0
while j < len(numbers):
if numbers[j] == min:
numbers.pop(j)
j += 1
print(ordered)
And the output:
[65, 66, 69, 72, 73, 78, 79, 79, 81, 82, 83, 84, 84, 84, 85]
So task1 is okay but task2 is only accomplished at some points not all.
I can't figure out why?
Thank you in advance for any help!
P.S.: I already solved the problem in another way but it just keeps bugging me why this posted idea of mine didn't work.
Others have provided shorter and more efficient ways of doing this, but you asked specifically what goes wrong with your approach. The problem is in this bit:
j = 0
while j < len(numbers):
if numbers[j] == min:
numbers.pop(j)
j += 1
What happens if min occurs twice back to back? Let's say for example that min == 3, and the list is [1, 3, 3, 7].
For j == 0, numbers[j] == 1 so we don't pop it, and increment j.
For j == 1, numbers[j] == 3 so we remove the element 1 and increment j. The list is now [1, 3, 7].
For j == 2, numbers[j] == 7 so we don't pop it, and we're done.
Whoops! We have skipped over the second 3 because it moved back one position when we popped its predecessor, while j moved forwards one position at the same time.
The solution is to only increment j if we didn't remove anything, because we need to re-check the element at position j after we removed its predecessor:
j = 0
while j < len(numbers):
if numbers[j] == min:
numbers.pop(j)
else:
j += 1
Let's verify that the loop is still guaranteed to terminate. Each iteration, either j becomes larger, or len(numbers) becomes smaller, so eventually they will meet and j < len(numbers) becomes false. So we're good.
You can use bubble sort.(If you need another sorting method, just replace it)
numbers = [84, 79, 66, 69, 79, 82, 78, 79, 84, 84, 79, 66, 69, 84,
72, 65, 84, 73, 83, 84, 72, 69, 81, 85, 69, 83, 84, 73, 79, 78]
def bubble_sort(arr):
n = len(arr)
for i in range(n-1):
for j in range(0, n-i-1):
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
no_dub = []
for i in arr:
if i not in no_dub:
no_dub.append(i)
return no_dub
bubble_sort(numbers)
The result:
[65, 66, 69, 72, 73, 78, 79, 81, 82, 83, 84, 85]
You need a small addition:
while j < len(numbers):
if numbers[j] == min:
numbers.pop(j)
j -= 1 #increment should not advance if you pop a number
j += 1
Then it will work
set will remove duplicates
sorted will sort it
sorted(list(set([65, 66, 69, 72, 73, 78, 79, 79, 81, 82, 83, 84, 84, 84, 85])))
[65, 66, 69, 72, 73, 78, 79, 81, 82, 83, 84, 85]
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]))
from functools import lru_cache
#lru_cache(maxsize=1000)
def recursiveFunc(x):
if x == 1:
return 1
elif x > 1 :
return recursiveFunc(x) + recursiveFunc(x+1) #This is the part i'm having doubts about.
for x in range(1, 101):
print(x, ":", recursiveFunc(x))
This functions is supposed to generate consecutive numbers starting from 1 to 100 using recursion.
Your problem is that you have to learn very well all the recursion story, it takes time... you have to visualize what the program is executing in every step. My advice is to draw the first times the stack buffer with every call of the function
The solution of your problem is:
def recursiveFunc(x):
if x == 1:
return 1
elif x > 1 :
return 1 + recursiveFunc(x-1) #This is the part I've changed.
for x in range(1, 101):
print(x, ":", recursiveFunc(x))
Why your doesn't work? Cause when the function calls return, return start the new function recursiveFunc(x)... but it's just the same of before! so there is an infinite loop.
Furthermore if you add like recursiveFunc(x+1) and you pass x that are positive you will never made the comparison x == 0 cause x it's growing call after call.
Here I'll try to clear things up for you :)
Writing a function that lists numbers from 1 to n is simple.
If we tried running this function
def recursiveFunc(i):
print(i)
recursiveFunc(i+1)
recursiveFunc(1)
It would print out 1, then 2, 3.... But would never stop.
1
2
3
...
To fix this we add a second parameter
def recursiveFunc(i, n):
if i > n:
return
print(i)
recursiveFunc(i+1)
recursiveFunc(1, 100)
This will escape the function when it passes n, in this case, 100
1
2
...
100
if you wanted to return the series rather than just print it out you could do something like this:
def recursiveFunc(i, n):
if i >= n:
return str(i)
return str(i) + ", " + str(recursiveFunc(i + 1, n))
print(recursiveFunc(1, 100))
Then the output would be
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