Related
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 1 year ago.
Improve this question
I have a list full of integers(it's not sorted) and I have 2 input:
-input no.1 the sum I want to get
-input no.2 the maximum number of usable element to get the sum
The sum can't be higher than the given value(input no.1) but can be less by -10. The number of used elements of the list can be equal to or less than the given value(input no.2).
from random import choice
def Diff(li1, li2):
return (list(list(set(li1)-set(li2)) + list(set(li2)-set(li1))))
def find_the_elements(current_sum, wanted_sum, used_elements, max_number_of_elements, n_o_elements):
solution = 0
while solution != 1:
elemnt=choice(Diff(elemts, used_elements))
used_elements.append(elemnt)
current_sum+=elemnt
n_o_elements+=1
if max_number_of_elements<=max_number_of_elements and current_sum in wanted_sum:
return used_elements
elif n_o_elements>max_number_of_elements or current_sum>wanted_sum.stop:
return -1
else:
x=find_the_elements(current_sum=current_sum, wanted_sum=wanted_sum, used_elements=used_elements, n_o_elements=n_o_elements, max_number_of_elements=max_number_of_elements)
if x!=-1:
return used_elements
elif x==-1:
return -1
elemts = [535, 508, 456, 612, 764, 628, 530, 709, 676, 546, 579, 676,
564, 565, 742, 657, 577, 514, 650, 590, 621, 642, 684, 567, 670, 609, 571, 655, 681, 615, 617, 569, 656, 615,
542, 711, 777, 763, 663, 657, 532, 630, 636, 445, 495, 567, 603, 598, 629, 651, 608, 653, 669, 603, 655, 622,
578, 551, 560, 712, 642, 637, 545, 631, 479, 614, 710, 458, 615, 659, 636, 578, 629, 622, 584, 582, 650, 636,
693, 527, 577, 711, 601, 530, 1028, 683, 589, 590, 670, 409,582, 635, 558, 607, 648, 542, 726, 534, 540, 590, 649, 482, 664, 629, 555, 596, 613, 572, 516, 479, 562, 452,
586]
max_no_elements = int(input())
wanted_sum = int(input())
solution = -1
while solution == -1:
solution = find_the_elements(current_sum=0, wanted_sum=range(wanted_sum - 10, wanted_sum + 1), used_elements=[], max_number_of_elements=max_no_elements, n_o_elements=0)
print(solution)
That's my solution for it but I think I should do it differently because originally I work with a much bigger list and each elements(integer) of the list is much 10-20x bigger.
Recursion with memoization (i.e. dynamic programing) is probably the best approach for this:
def closeSum(A,S,N,p=0,memo=None):
if not N: return [],0
if memo is None: memo = dict() # memoization
if (S,N,p) in memo: return memo[S,N,p]
best,bestSum = [],0
for i,a in enumerate(A[p:],p): # combine remaining elements for sum
if a>S: continue # ignore excessive values
if a == S: return [a],a # end on perfect match
r = [a] + closeSum(A,S-a,N-1,i+1,memo)[0] # extend sum to get closer
sr = sum(r)
if sr+10>=S and sr>bestSum: # track best so far
best,bestSum = r,sr
memo[S,N,p]=(best,sum(best)) # memoization
return best,sum(best)
output:
elemts = [535, 508, 456, 612, 764, 628, 530, 709, 676, 546, 579, 676,
564, 565, 742, 657, 577, 514, 650, 590, 621, 642, 684, 567, 670, 609, 571, 655, 681, 615, 617, 569, 656, 615,
542, 711, 777, 763, 663, 657, 532, 630, 636, 445, 495, 567, 603, 598, 629, 651, 608, 653, 669, 603, 655, 622,
578, 551, 560, 712, 642, 637, 545, 631, 479, 614, 710, 458, 615, 659, 636, 578, 629, 622, 584, 582, 650, 636,
693, 527, 577, 711, 601, 530, 1028, 683, 589, 590, 670, 409,582, 635, 558, 607, 648, 542, 726, 534, 540, 590, 649, 482, 664, 629, 555, 596, 613, 572, 516, 479, 562, 452,
586]
closeSum(elemts,1001,3)
[456, 545], 1001
closeSum(elemts,5522,7)
[764, 742, 777, 763, 712, 1028, 726], 5512
closeSum(elemts,5522,10)
[535, 508, 456, 612, 764, 628, 530, 546, 409, 534], 5522
It works relatively fast when there is an exact match but still takes a while for the larger values/item counts when it doesn't.
Note that there is still room for some optimization such as keeping track of the total of remaining elements (from position p) and exiting if they can't add up to the target sum.
I have something along the lines of this dict:
{10: [891, 506, 714, 430, 294, 659, 430, 430, 375, 430, 294, 714, 1510, 1049, 847, 430, 430, 430, 1410, 1657], 12: [676, 466, 719, 727, 573, 1202, 466, 719, 573, 885, 573, 573, 573, 573, 518, 518, 573, 573, 1465, 466]}
I am trying to plot a graph where the x axis has the keys, (i.e: 10,12,14...) and the y axis represents the average of the list corresponding with the key and I want to show some bars which represent the quartiles or the possible range? Anyone have any idea how I can go about doing that?
This is in Python btw.
Any help would be appreciated.
import matplotlib.pyplot as plt
data = {10: [891, 506, 714, 430, 294, 659, 430, 430, 375, 430, 294, 714, 1510, 1049, 847, 430, 430, 430, 1410, 1657],
12: [676, 466, 719, 727, 573, 1202, 466, 719, 573, 885, 573, 573, 573, 573, 518, 518, 573, 573, 1465, 466]}
keys = sorted(data) # keys in a defined order
plt.boxplot([data[k] for k in keys], positions=keys) # box-and-whisker plot
plt.plot(keys, [sum(data[k]) / len(data[k]) for k in keys], '-o') # line for the mean
plt.savefig('nice-box-plots')
Adding whis=(10, 90) as argument to plt.boxplot will put the whiskers to the 10 and 90%tile, see the doc of boxplots.
I suggest you turn your data into a pandas dataframe, carry on all calculation on that dataframe and plot. For example:
df = pd.DataFrame(data)
plot_data = df.agg(['mean', 'std']).T
plt.errorbar(plot_data.index, plot_data['mean'], yerr=plot_data['std'])
Output:
I have a 2D numpy array, z, in which I would like to assign values to nan based on the equation of a line +/- a width of 20. I am trying to implement the Raman 2nd scattering correction as it is done by the eem_remove_scattering method in the eemR package listed here:
https://cran.r-project.org/web/packages/eemR/vignettes/introduction.html
but the method isn't visible.
import numpy as np
ex = np.array([240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300,
305, 310, 315, 320, 325, 330, 335, 340, 345, 350, 355, 360, 365,
370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430,
435, 440, 445, 450])
em = np.array([300, 302, 304, 306, 308, 310, 312, 314, 316, 318, 320, 322, 324,
326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350,
352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 376,
378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, 400, 402,
404, 406, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428,
430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, 454,
456, 458, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480,
482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506,
508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532,
534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558,
560, 562, 564, 566, 568, 570, 572, 574, 576, 578, 580, 582, 584,
586, 588, 590, 592, 594, 596, 598, 600])
X, Y = np.meshgrid(ex, em)
z = np.sin(X) + np.cos(Y)
The equation that I would like to apply is em = - 2 ex/ (0.00036*ex-1) + 500.
I want to set every value in the array that intersects this line (+/- 20 ) to be set to nans. Its simple enough to set a single element to nans, but I havent been able to locate a python function to apply this equation to the array and only set values that intersect with this line to nans.
The desired output would be a new array with the same dimensions as z, but with the values that intersect the line equivalent to nan. Any suggestions on how to proceed are greatly appreciated.
Use np.where in the form np.where( "condition for intersection", np.nan, z):
zi = np.where( np.abs(-2*X/(0.00036*X-1) + 500 - Y) <= 20, np.nan, z)
As a matter of fact, there are no intersections here because (0.00036*ex-1) is close to -1 for all your values, which makes - 2*ex/(0.00036*ex-1) close to 2*ex, and adding 500 brings this over any values you have in em. But in principle this works.
Also, I suspect that the goal you plan to achieve by setting those values to NaN would be better achieved by using a masked array.
Firstly, here is the script:
import numpy as np
import osgeo.gdal
import os
ArbitraryXCoords = np.arange(435531.30622598,440020.30622598,400)
ArbitraryYCoords = np.arange(5634955.28972479,5638945.28972479,400)
os.chdir('/home/foo/GIS_Summer2013')
dataset = osgeo.gdal.Open("Raster_DEM")
gt = dataset.GetGeoTransform()
def XAndYArrays(spacing):
XPoints = np.arange(gt[0], gt[0] + dataset.RasterXSize * gt[1], spacing)
YPoints = np.arange(gt[3] + dataset.RasterYSize * gt[5], gt[3], spacing)
return (XPoints, YPoints)
def RasterPoints(XCoords,YCoords):
a=[]
for row in YCoords:
for col in XCoords:
rasterx = int((col - gt[0]) / gt[1])
rastery = int((row - gt[3]) / gt[5])
band = int(dataset.GetRasterBand(1).ReadAsArray(rasterx,rastery, 1, 1)[0][0])
a[len(a):] = [band]
foo = np.asarray(a)
bar = foo.reshape(YCoords.size,XCoords.size)
return bar
When I load the script that is presented above, I am unable to use the output from the function XAndYArrays as input in the function RasterPoints. But I am able to use the numpy.ndarray that I have defined manually as input in the function RasterPoints. But this is not good enough. I need to be able to use the output from XAndYArrays as input in RasterPoints.
Here are the commands that I used at the PyDev interactive console:
>>> Eastings,Northings = XAndYArrays(400)
>>> Eastings
Out[1]:
array([ 435530.30622598, 435930.30622598, 436330.30622598,
436730.30622598, 437130.30622598, 437530.30622598,
437930.30622598, 438330.30622598, 438730.30622598,
439130.30622598, 439530.30622598, 439930.30622598])
>>> Northings
Out[1]:
array([ 5634954.28972479, 5635354.28972479, 5635754.28972479,
5636154.28972479, 5636554.28972479, 5636954.28972479,
5637354.28972479, 5637754.28972479, 5638154.28972479,
5638554.28972479, 5638954.28972479])
>>> RasterPoints(Eastings, Northings)
ERROR 5: MergedDEM_EPSG3159_Reduced, band 1: Access window out of range in RasterIO(). Requested (0,246) of size 1x1 on raster of 269x246.
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/IPython/core/interactiveshell.py", line 2538, in run_code
exec code_obj in self.user_global_ns, self.user_ns
File "<ipython-input-1-326be9918188>", line 1, in <module>
RasterPoints(Eastings, Northings)
File "/home/foo/GIS_Summer2013/src/22July_StackOverflowQuestion.py", line 23, in RasterPoints
band = int(dataset.GetRasterBand(1).ReadAsArray(rasterx,rastery, 1, 1)[0][0])
TypeError: 'NoneType' object has no attribute '__getitem__'
>>> RasterPoints(ArbitraryXCoords, ArbitraryYCoords)
Out[1]:
array([[422, 422, 431, 439, 428, 399, 410, 395, 398, 413, 409, 386],
[414, 428, 421, 430, 426, 403, 409, 410, 406, 408, 412, 406],
[420, 428, 427, 424, 408, 406, 428, 420, 408, 410, 409, 420],
[392, 418, 426, 430, 414, 428, 430, 418, 433, 414, 402, 399],
[400, 411, 420, 406, 401, 405, 398, 420, 419, 400, 401, 414],
[408, 421, 418, 428, 399, 398, 405, 412, 421, 406, 395, 397],
[399, 404, 398, 401, 400, 399, 399, 398, 398, 419, 399, 395],
[401, 410, 407, 407, 404, 400, 398, 397, 397, 399, 400, 398],
[400, 410, 418, 405, 401, 400, 397, 398, 400, 398, 397, 396],
[389, 387, 399, 408, 423, 400, 407, 398, 411, 408, 410, 420]])
>>> print "partial success"
partial success
You are trying to read a pixel location which doesn't exist because its outside the raster dimensions.
Try calculating your Ypoints with:
YPoints = np.arange(gt[3] + (ds.RasterYSize-1) * gt[5], gt[3], abs(gt[5]))
Your RasterPoints function is really bad practice. You're accessing all array values 1 at the time, store them in a list and then make an array of it. That makes no sense at all.
Furthermore i think its good practice on SO to close/resolve previous questions before opening another one.
This question already has answers here:
Print all even numbers in a list until a given number
(6 answers)
Closed 10 years ago.
My (simple) code gives an error at the last line. What am I doing wrong?
The question:
Loop through and print out all even numbers from the numbers list in the same order they are received. Don't print any numbers that come after 237 in the sequence.
What am I doing wrong?
numbers = [951, 402, 984, 651, 360, 69, 408, 319, 601, 485, 980, 507, 725, 547, 544,
615, 83, 165, 141, 501, 263, 617, 865, 575, 219, 390, 984, 592, 236, 105, 942, 941,
386, 462, 47, 418, 907, 344, 236, 375, 823, 566, 597, 978, 328, 615, 953, 345,
399, 162, 758, 219, 918, 237, 412, 566, 826, 248, 866, 950, 626, 949, 687, 217,
815, 67, 104, 58, 512, 24, 892, 894, 767, 553, 81, 379, 843, 831, 445, 742, 717,
958, 609, 842, 451, 688, 753, 854, 685, 93, 857, 440, 380, 126, 721, 328, 753, 470,
743, 527]
# your code goes here
for number in numbers:
if number <= 237 and number % 2 == 0:
continue
print numbers
You need to lose the continue, it'll move the loop to the next iteration instead. I think you were looking for break (when you find 237).
Just print number, but do make print() a function for Python 3.
for number in numbers:
if number == 237:
break
if number % 2 == 0:
print(number)