Replacing values in array with decimals - python

I have an array arr100 = np.ones(100). I need to replace these values with decimals,
where arr100[0] has a value 1, arr100[1] = 1/2, arr100[2] = 1/3,
and so on until arr100[99] = 1/100.
How to do this using a for loop in Python?

You can do something like this:
arr100 = np.ones(100)
for n in range(1, 101):
arr100[n-1] /= n
which changes arr100 to:
array([1. , 0.5 , 0.33333333, 0.25 , 0.2 ,
0.16666667, 0.14285714, 0.125 , 0.11111111, 0.1 ,
[....]

for i in range(101):
arr100[i] = 1/arr100[i]

You dont actually need an imported module (numpy) to do this. It can be done in a natural python list.
so you can just do this:
result = [1/(i+1) for i in range(100)]
print(result)
which returns this:
[1.0, 0.5, 0.3333333333333333, 0.25, 0.2, 0.16666666666666666, 0.14285714285714285, 0.125, 0.1111111111111111, 0.1, 0.09090909090909091, 0.08333333333333333, 0.07692307692307693, 0.07142857142857142, 0.06666666666666667, 0.0625, 0.058823529411764705, 0.05555555555555555, 0.05263157894736842, 0.05, 0.047619047619047616, 0.045454545454545456, 0.043478260869565216, 0.041666666666666664, 0.04, 0.038461538461538464, 0.037037037037037035, 0.03571428571428571, 0.034482758620689655, 0.03333333333333333, 0.03225806451612903, 0.03125, 0.030303030303030304, 0.029411764705882353, 0.02857142857142857, 0.027777777777777776, 0.02702702702702703, 0.02631578947368421, 0.02564102564102564, 0.025, 0.024390243902439025, 0.023809523809523808, 0.023255813953488372, 0.022727272727272728, 0.022222222222222223, 0.021739130434782608, 0.02127659574468085, 0.020833333333333332, 0.02040816326530612, 0.02, 0.0196078431372549, 0.019230769230769232, 0.018867924528301886, 0.018518518518518517, 0.01818181818181818, 0.017857142857142856, 0.017543859649122806, 0.017241379310344827, 0.01694915254237288, 0.016666666666666666, 0.01639344262295082, 0.016129032258064516, 0.015873015873015872, 0.015625, 0.015384615384615385, 0.015151515151515152, 0.014925373134328358, 0.014705882352941176, 0.014492753623188406, 0.014285714285714285, 0.014084507042253521, 0.013888888888888888, 0.0136986301369863, 0.013513513513513514, 0.013333333333333334, 0.013157894736842105, 0.012987012987012988, 0.01282051282051282, 0.012658227848101266, 0.0125, 0.012345679012345678, 0.012195121951219513, 0.012048192771084338, 0.011904761904761904, 0.011764705882352941, 0.011627906976744186, 0.011494252873563218, 0.011363636363636364, 0.011235955056179775, 0.011111111111111112, 0.01098901098901099, 0.010869565217391304, 0.010752688172043012, 0.010638297872340425, 0.010526315789473684, 0.010416666666666666, 0.010309278350515464, 0.01020408163265306, 0.010101010101010102, 0.01]
or you could do this to get the same:
import numpy as np
arr100 = np.ones(100)
for i,j in enumerate(arr100):
arr100[i] = 1/(i+1)
print(arr100)

Related

Append in an array results in a list Python

I have the following code
points=candies
K=5
centers = []
for i in range(K):
centers.append(random.choice(points))
centers
which results in basically a list of arrays
[array([0.6 , 0.92, 0.29]),
array([0.99, 0.23, 0.45]),
array([0.65, 0.6 , 0.03]),
array([0.21, 0.22, 0.55]),
array([0.62, 0.84, 0.83])]
What I want would be a single array like
array[[0.6 , 0.92, 0.29],
[0.99, 0.23, 0.45],
[0.65, 0.6 , 0.03],
[0.21, 0.22, 0.55],
[0.62, 0.84, 0.83]]
What do I have to change?
Either convert the list of arrays to a 2D array:
np.array(centers)
Or start right from an empty array and populate it:
centers = np.empty((K,3))
for i in range(K):
centers[i] = random.choice(points)

Finding the probability of a variable in collection of lists

I have a selection of lists of variables
import numpy.random as npr
w = [0.02, 0.03, 0.05, 0.07, 0.11, 0.13, 0.17]
x = 1
y = False
z = [0.12, 0.2, 0.25, 0.05, 0.08, 0.125, 0.175]
v = npr.choice(w, x, y, z)
I want to find the probability of the value V being a selection of variables eg; False or 0.12.
How do I do this.
Heres what I've tried;
import numpy.random as npr
import math
w = [0.02, 0.03, 0.05, 0.07, 0.11, 0.13, 0.17]
x = 1
y = False
z = [0.12, 0.2, 0.25, 0.05, 0.08, 0.125, 0.175]
v = npr.choice(w, x, y, z)
from collections import Counter
c = Counter(0.02, 0.03, 0.05, 0.07, 0.11, 0.13, 0.17,1,False,0.12, 0.2, 0.25, 0.05, 0.08, 0.125, 0.175)
def probability(0.12):
return float(c[v]/len(w,x,y,z))
which I'm getting that 0.12 is an invalid syntax
There are several issues in the code, I think you want the following:
import numpy.random as npr
import math
from collections import Counter
def probability(v=0.12):
return float(c[v]/len(combined))
w = [0.02, 0.03, 0.05, 0.07, 0.11, 0.13, 0.17]
x = [1]
y = [False]
z = [0.12, 0.2, 0.25, 0.05, 0.08, 0.125, 0.175]
combined = w + x + y + z
v = npr.choice(combined)
c = Counter(combined)
print(probability())
print(probability(v=0.05))
1) def probability(0.12) does not make sense; you will have to pass a variable which can also have a default value (above I use 0.12)
2) len(w, x, y, z) does not make much sense either; you probably look for a list that combines all the elements of w, x, y and z. I put all of those in the list combined.
3) One would also have to put in an additional check, in case the user passes e.g. v=12345 which is not included in combined (I leave this to you).
The above will print
0.0625
0.125
which gives the expected outcome.

How to generate list of floats in descending order that sum to 1?

I want to generate a list of floats of size M, where each item in the list is greater than the other proceeding items i.e. Descending order. and the sum of the list must sum to 1. and for the same M magnitude can I generate more than one list that obey to the given constraints.
I'm thinking of an equation in the following form:
Xi+1 = compute([Xi,Xi-1...X0], M, Random)
But I am not able to figure out the extent of this function. Thank you in advance.
okay, so let's pick 10 random numbers from 0 to 10, and sort them. Then compute sum and rebuild a new list with each element divided by this sum:
import random
# create a non-normalized ascending list of numbers
lst = sorted(random.uniform(0,10) for _ in range(10))
# compute the sum
temp_sum = sum(lst)
# now divide each member by the sum to normalize the list
lst = [i/temp_sum for i in lst]
print(lst,sum(lst))
one output could be:
[0.0340212528820301, 0.05665995400192079, 0.07733861892990018,
0.07752841352220373, 0.08556431469182045, 0.11628857362899164,
0.11706017358757258, 0.12523809404875455, 0.14272942597136748,
0.16757117873543856] 1.0
The sum could be not exactly 1 because of floating point inaccuracy, but will be very close.
If you want something that is mathematically predictable...
def makeDescendingUnitArray(length: int):
if (not isinstance(length, int)) or (length < 1):
raise ValueError("Array Length must be an int with a value of at least 1")
if length == 1:
return [1]
else:
constant = 1
output = list()
for x in range(length - 2):
constant /= 2
output.append(constant)
return output + [2*constant/3, constant/3]
for arrayLength in range(1, 10):
array = makeDescendingUnitArray(arrayLength)
print(array)
Produces the following arrays...
[1]
[0.6666666666666666, 0.3333333333333333]
[0.5, 0.3333333333333333, 0.16666666666666666]
[0.5, 0.25, 0.16666666666666666, 0.08333333333333333]
[0.5, 0.25, 0.125, 0.08333333333333333, 0.041666666666666664]
[0.5, 0.25, 0.125, 0.0625, 0.041666666666666664, 0.020833333333333332]
[0.5, 0.25, 0.125, 0.0625, 0.03125, 0.020833333333333332, 0.010416666666666666]
[0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.010416666666666666, 0.005208333333333333]
[0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.005208333333333333, 0.0026041666666666665]
If you want a mathematically predictable one-liner, then there's this...
(loop to show you what it looks like)
for length in range(1, 10):
array = [2*x/(length * (length + 1)) for x in range(length,0,-1)]
print(sum(array), array)
This produces the following output. Note that this is just as susceptible to the floating point rounding errors as all of the other algorithms. There are some better and some worse algorithms, but at some point, they'll all have some error.
Sum: 1.0 Array: [1.0]
Sum: 1.0 Array: [0.6666666666666666, 0.3333333333333333]
Sum: 0.9999999999999999 Array: [0.5, 0.3333333333333333, 0.16666666666666666]
Sum: 0.9999999999999999 Array: [0.4, 0.3, 0.2, 0.1]
Sum: 1.0 Array: [0.3333333333333333, 0.26666666666666666, 0.2, 0.13333333333333333, 0.06666666666666667]
Sum: 0.9999999999999998 Array: [0.2857142857142857, 0.23809523809523808, 0.19047619047619047, 0.14285714285714285, 0.09523809523809523, 0.047619047619047616]
Sum: 1.0 Array: [0.25, 0.21428571428571427, 0.17857142857142858, 0.14285714285714285, 0.10714285714285714, 0.07142857142857142, 0.03571428571428571]
Sum: 1.0 Array: [0.2222222222222222, 0.19444444444444445, 0.16666666666666666, 0.1388888888888889, 0.1111111111111111, 0.08333333333333333, 0.05555555555555555, 0.027777777777777776]
Sum: 0.9999999999999999 Array: [0.2, 0.17777777777777778, 0.15555555555555556, 0.13333333333333333, 0.1111111111111111, 0.08888888888888889, 0.06666666666666667, 0.044444444444444446, 0.022222222222222223]

Plot Chi-squared for the optimal order of a fit with polynomial

I have the following code, in which DGauss is a function that generates the expected values. The two arrays, on the other hand, allow me to generate a distribution, that I take as observed values. The code, based on the observed values, extracts a polynomial (for the moment of the seventh degree) that describes its trend.
import numpy as np
import matplotlib
matplotlib.use('qt5Agg')
import matplotlib.pyplot as plt
import scipy
from scipy.optimize import curve_fit
from scipy import interpolate
def DGauss(x,I1,I2,sigma1,sigma2):
return I1*np.exp(-x*x/(2*sigma1*sigma1)) + I2*np.exp(-x*x/(2*sigma2*sigma2))
Pos = np.array([3.28, 3.13, 3.08, 3.03, 2.98, 2.93, 2.88, 2.83, 2.78, 2.73, 2.68,
2.63, 2.58, 2.53, 2.48, 2.43, 2.38, 2.33, 2.28, 2.23, 2.18, 2.13,
2.08, 2.03, 1.98, 1.93, 1.88, 1.83, 1.78, 1.73, 1.68, 1.63, 1.58,
1.53, 1.48, 1.43, 1.38, 1.33, 1.28, 1.23, 1.18, 1.13, 1.08, 1.03,
0.98, 0.93, 0.88, 0.83, 0.78, 0.73, 0.68, 0.63, 0.58, 0.53, 0.48,
0.43, 0.38, 0.33, 0.28, 0.23, 0.18, 0.13, 0.08, 0.03])
Val = np.array([0.00986279, 0.01529543, 0.0242624 , 0.0287456 , 0.03238484,
0.03285927, 0.03945234, 0.04615091, 0.05701618, 0.0637672 ,
0.07194268, 0.07763934, 0.08565687, 0.09615262, 0.1043281 ,
0.11350606, 0.1199406 , 0.1260062 , 0.14093328, 0.15079665,
0.16651464, 0.18065023, 0.1938894 , 0.2047541 , 0.21794024,
0.22806706, 0.23793043, 0.25164404, 0.2635118 , 0.28075974,
0.29568682, 0.30871501, 0.3311846 , 0.34648062, 0.36984661,
0.38540666, 0.40618835, 0.4283945 , 0.45002014, 0.48303911,
0.50746062, 0.53167057, 0.5548792 , 0.57835128, 0.60256181,
0.62566436, 0.65704847, 0.68289386, 0.71332794, 0.73258027,
0.769608 , 0.78769989, 0.81407275, 0.83358852, 0.85210239,
0.87109068, 0.89456217, 0.91618782, 0.93760247, 0.95680234,
0.96919757, 0.9783219 , 0.98486193, 0.9931429 ])
f = np.linspace(-9,9,2*len(Pos))
plt.errorbar(Pos, Val, xerr=0.02, yerr=2.7e-3, fmt='o')
popt, pcov = curve_fit(DGauss, Pos, Val)
plt.plot(f, DGauss(f, *popt), '--', label='Double Gauss')
x = Pos
y = Val
z, w = np.polyfit(x, y, 7, full=False, cov=True)
p = np.poly1d(z)
u = np.array(p)
xp = np.linspace(0, 6, 100)
_ = plt.plot(xp, p(xp), '-', color='darkviolet')
x = symbols('x')
list = u[::-1]
poly = sum(S("{:7.3f}".format(v))*x**i for i, v in enumerate(list))
eq_latex = sympy.printing.latex(poly)
print(eq_latex)
chiSquares = []
dofs = 10
for i in np.arange(1,dofs+1):
z = np.polyfit(x, y, i, full=False, cov=False)
chi = np.sum((np.polyval(z, x) - y) ** 2) / np.std(y)
chinorm = chi/i
chiSquares.append(chinorm)
plt.plot(np.arange(1,dofs+1),chiSquares)
plt.show()
What I expect are different chi squared distributions, but it returns only the plot of a broken line, of which I do not understand its meaning. Could someone help me kindly?

Chi-squared for the optimal order of a fit with polynomial

I have the following code, in which DGauss is a function that generates the expected values. The two arrays, on the other hand, allow me to generate a distribution, that I take as observed values.
The code, based on the observed values, extracts a polynomial (for the moment of the seventh degree) that describes its trend.
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def DGauss(x,I1,I2,sigma1,sigma2):
return I1*np.exp(-x*x/(2*sigma1*sigma1)) + I2*np.exp(-x*x/(2*sigma2*sigma2))
Pos = np.array([3.28, 3.13, 3.08, 3.03, 2.98, 2.93, 2.88, 2.83, 2.78, 2.73, 2.68,
2.63, 2.58, 2.53, 2.48, 2.43, 2.38, 2.33, 2.28, 2.23, 2.18, 2.13,
2.08, 2.03, 1.98, 1.93, 1.88, 1.83, 1.78, 1.73, 1.68, 1.63, 1.58,
1.53, 1.48, 1.43, 1.38, 1.33, 1.28, 1.23, 1.18, 1.13, 1.08, 1.03,
0.98, 0.93, 0.88, 0.83, 0.78, 0.73, 0.68, 0.63, 0.58, 0.53, 0.48,
0.43, 0.38, 0.33, 0.28, 0.23, 0.18, 0.13, 0.08, 0.03])
Val = np.array([0.00986279, 0.01529543, 0.0242624 , 0.0287456 , 0.03238484,
0.03285927, 0.03945234, 0.04615091, 0.05701618, 0.0637672 ,
0.07194268, 0.07763934, 0.08565687, 0.09615262, 0.1043281 ,
0.11350606, 0.1199406 , 0.1260062 , 0.14093328, 0.15079665,
0.16651464, 0.18065023, 0.1938894 , 0.2047541 , 0.21794024,
0.22806706, 0.23793043, 0.25164404, 0.2635118 , 0.28075974,
0.29568682, 0.30871501, 0.3311846 , 0.34648062, 0.36984661,
0.38540666, 0.40618835, 0.4283945 , 0.45002014, 0.48303911,
0.50746062, 0.53167057, 0.5548792 , 0.57835128, 0.60256181,
0.62566436, 0.65704847, 0.68289386, 0.71332794, 0.73258027,
0.769608 , 0.78769989, 0.81407275, 0.83358852, 0.85210239,
0.87109068, 0.89456217, 0.91618782, 0.93760247, 0.95680234,
0.96919757, 0.9783219 , 0.98486193, 0.9931429 ])
f = np.linspace(-9,9,2*len(Pos))
plt.errorbar(Pos, Val, xerr=0.02, yerr=2.7e-3, fmt='o')
popt, pcov = curve_fit(DGauss, Pos, Val)
plt.plot(xfull, DGauss(f, *popt), '--', label='Double Gauss')
x = Pos
y = Val
#z, w = np.polyfit(x, y, 7, full=False, cov=True)
p = np.poly1d(z)
u = np.array(p)
xp = np.linspace(1, 6, 100)
_ = plt.plot(xp, p(xp), '-', color='darkviolet')
x = symbols('x')
list = u[::-1]
poly = sum(S("{:7.3f}".format(v))*x**i for i, v in enumerate(list))
eq_latex = sympy.printing.latex(poly)
print(eq_latex)
#LOOP SUGGESTED BY #Fourier
dof = [1,2,3,4,5,6,7,8,9,10]
for i in dof:
z = np.polyfit(x, y, i, full=False, cov=True)
chi = np.sum((np.polyval(z, x) - y) ** 2)
chinorm = chi/i
plt.plot(chinorm)
What I would like to do now is to make a fit by varying the order of the polynomial to figure out which is the minimum order I need to have a good fit and not exceed the number of free parameters. In particular, I would like to make this fit with different orders and plot the chi-squared, which must be normalized with respect to the number of degrees of freedom.
Could someone help me kindly?
Thanks!
Based on the posted code this should work for your purpose:
chiSquares = []
dofs = 10
for i in np.arange(1,dofs+1):
z = np.polyfit(x, y, i, full=False, cov=False)
chi = np.sum((np.polyval(z, x) - y) ** 2) / np.std(y) #ideally you should divide this using an error for Val array
chinorm = chi/i
chiSquares.append(chinorm)
plt.plot(np.arange(1,dofs+1),chiSquares)
If not evident from the plot, you can further use the F-test to check how much dof is really needed:
n = len(y)
for d, (rss1,rss2) in enumerate(zip(chiSquares,chiSquares[1:])):
p1 = d + 1
p2 = d + 2
F = (rss1-rss2/(p2-p1)) / (rss2/(n-p2))
p = 1.0 - scipy.stats.f.cdf(F,p1,p2)
print 'F-stats: {:.3f}, p-value: {:.5f}'.format(F,p)

Categories

Resources