How to fix 'float' object is not iterable? - python

I write a function phix that is input a x and N, then get a summation x_new.
def phix(x, N):
lam=np.floor(N**(1/3))
x_new=0
for i in range(0, int(lam)):
if (i+1)*N**(-1/3)>x>i*N**(-1/3):
x_new=x_new+(2*i+1)/(2*N**(1/3))
return x_new
Here is a error:
N=1
x = np.random.random_sample(N)
x_new=phix(x, N)
x_val = np.array(list(Counter(x_new).keys()))
TypeError: 'float' object is not iterable
In fact, I want to input N=2 or N=3 and phix(x, N) return a vector of x_new not a value. I am not sure how to do that? I try the following code but it seems does not work.
def phix(x,N):
lam=np.floor(N**(1/3))
x_new=np.zeros(N)
for i in range(0, N):
x_newa=0
for j in range(0, int(lam)):
if (j+1)*N**(-1/3)>x[i]>j*N**(-1/3):
x_newa=x_newa+(2*j+1)/(2*N**(1/3))
x_new[i]=x_newa
return(x_new)
I do the following example.
N=3
x = np.random.random_sample(N)
x_new=phix(x,N)
print(x_new)
But it shows all same values
[0.34668064 0.34668064 0.34668064]

OK, I don't know why you have two loops in there. There only needs to be one loop, running from 0 to cube-root(N). The function should accept one value (x) and return one value. The value being added does not depend on x at all - x is only used to determine whether an element of the summation is included or not.
So, I believe this produces the result you want. For each of your random values of x, there is one result. And as I said, when N is 3, the inner loop only runs once, so the result can ONLY be 0 or 0.34668. When N=1000 there is a bit more variation, but there are still only 10! possible results.
import numpy as np
def phix(x,N):
ncr = N**(1/3)
lam = int(ncr)
sumx = 0
for i in range(lam):
if i/ncr < x < (i+1)/ncr:
sumx += (i+i+1) / (2*ncr)
return sumx
N = 1000
x = np.random.random_sample(N)
for x1 in x:
print( x1, phix(x1,N) )
Output (truncated):
0.16252465361984203 0.15000000000000002
0.6527047022599177 0.6500000000000001
0.7733129495624551 0.7500000000000001
0.03800607206261242 0.05000000000000001
0.7116353720754358 0.7500000000000001
0.01845039536391846 0.05000000000000001
0.3398936159178093 0.3500000000000001
0.44312359112375477 0.45000000000000007
0.3010799287710728 0.3500000000000001
0.37401793425303764 0.3500000000000001
0.7049621859196674 0.7500000000000001
0.5044002562214386 0.55
0.30073336035132303 0.3500000000000001
0.31630770524340746 0.3500000000000001
0.8465422342801152 0.8500000000000002
0.39679187879066746 0.3500000000000001
0.10910213537513935 0.15000000000000002
0.8932112016365839 0.8500000000000002
0.9858585971124458 0
0.49024772936880123 0.45000000000000007
(993 more)
import numpy as np
def phix(x,N):
ncr = N**(1/3)
lam = int(ncr)
sumx = 0
for i in range(lam):
if i/ncr < x < (i+1)/ncr:
sumx += (i+i+1) / (2*ncr)
return sumx
N = 1000
x = np.random.random_sample(N)
for x1 in x:
print( x1, phix(x1,N) )

Related

Python implementation of Matlab Code - Finite Difference Method

Given this Matlab Code created by my teacher:
function [] = explicitWave(T,L,N,J)
% Explicit method for the wave eq.
% T: Length time-interval
% L: Length x-interval
% N: Number of time-intervals
% J: Number of x-intervals
k=T/N;
h=L/J;
r=(k*k)/(h*h);
k/h
x=linspace(0,L,J+1); % number of points = number of intervals + 1
uOldOld=f(x); % solution two time-steps backwards. Initial condition
disp(uOldOld)
uOld=zeros(1,length(x)); % solution at previuos time-step
uNext=zeros(1,length(x));
% First time-step
for j=2:J
uOld(j)=(1-r)*f(x(j))+r/2*(f(x(j+1))+f(x(j-1)))+k*g(x(j));
end
% Remaining time-steps
for n=0:N-1
for j=2:J
uNext(j)=2*(1-r)*uOld(j)+r*(uOld(j+1)+uOld(j-1))-uOldOld(j);
end
uOldOld=uOld;
uOld=uNext;
end
plot(x,uNext,'r')
end
I tried to implement this in Python by using this code:
import numpy as np
import matplotlib.pyplot as plt
def explicit_wave(f, g, T, L, N, J):
"""
:param T: Length of Time Interval
:param L: Length of X-interval
:param N: Number of time intervals
:param J: Number of X-intervals
:return:
"""
k = T/N
h = L/J
r = (k**2) / (h**2)
x = np.linspace(0, L, J+1)
Uoldold = f(x)
Uold = np.zeros(len(x))
Unext = np.zeros(len(x))
for j in range(1, J):
Uold[j] = (1-r)*f(x[j]) + (r/2)*(f(x[j+1]) + f(x[j-1])) + k*g(x[j])
for n in range(N-1):
for j in range(1, J):
Unext[j] = 2*(1-r) * Uold[j]+r*(Uold[j+1]+Uold[j-1]) - Uoldold[j]
Uoldold = Uold
Uold = Unext
plt.plot(x, Unext)
plt.show()
return Unext, x
However when I run the code with the same inputs, I get different results when plotting them. My inputs:
g = lambda x: -np.sin(2*np.pi*x)
f = lambda x: 2*np.sin(np.pi*x)
T = 8.0
L = 1.0
J = 60
N = 480
Python plot result compared to exact result. The x-es represent the actual solution, and the red line is the function:
Matlab plot result , x-es represent the exact solution and the red line is the function:
Could you see any obvious errors I might have made when translating this code?
In case anyone needs the exact solution:
exact = lambda x,t: 2*np.sin(np.pi*x)*np.cos(np.pi*t) - (1/(2*np.pi))*np.sin(2*np.pi*x)*np.sin(2*np.pi*t)
I found the error through debugging. The main problem here is the code:
Uoldold = Uold
Uold = Unext
So in Python when you define a new variable as equal to an older variable, they become references to each other (i.e dependent on each other). Let me illustrate this as an example consisting of lists:
a = [1,2,3,4]
b = a
b[1] = 10
print(a)
>> [1, 10, 3, 4]
So the solution here was to use .copy()
Resulting in this:
Uoldold = Uold.copy()
Uold = Unext.copy()

Python: How to get Cumulative distribution function for continuous data values?

I have a set of data values, and I want to get the CDF (cumulative distribution function) for that data set.
Since this is a continuous variable, we can't use binning approach as mentioned in (How to get cumulative distribution function correctly for my data in python?). So I came up with following approach.
import scipy.stats as st
def trapezoidal_2(ag, a, b, n):
h = np.float(b - a) / n
s = 0.0
s += ag(a)[0]/2.0
for i in range(1, n):
s += ag(a + i*h)[0]
s += ag(b)[0]/2.0
return s * h
def get_cdf(data):
a = np.array(data)
ag = st.gaussian_kde(a)
cdf = [0]
x = []
k = 0
max_data = max(data)
while (k < max_data):
x.append(k)
k = k + 1
sum_integral = 0
for i in range(1, len(x)):
sum_integral = sum_integral + (trapezoidal_2(ag, x[i - 1], x[i], 2))
cdf.append(sum_integral)
return x, cdf
This is how I use this method.
b = 1
data = st.pareto.rvs(b, size=10000)
data = list(data) x_cdf, y_cdf = get_cdf(data)
Ideally I should get a value close to 1 at the end of y_cdf list. But I get a value close to 0.57.
What is going wrong here? Is my approach correct?
Thanks.
The value of the cdf at x is the integral of the pdf between -inf and x, but you are computing it between 0 and x. Maybe you are assuming that the pdf is 0 for x < 0 but it is not:
rs = np.random.RandomState(seed=52221829)
b = 1
data = st.pareto.rvs(b, size=10000, random_state=rs)
ag = st.gaussian_kde(data)
x = np.linspace(-100, 100)
plt.plot(x, ag.pdf(x))
So this is probably what's going wrong here: you not checking your assumptions.
Your code for computing the integral is painfully slow, there are better ways to do this with scipy but gaussian_kde provides the method integrate_box_1d to integrate the pdf. If you take the integral from -inf everything looks right.
cdf = np.vectorize(lambda x: ag.integrate_box_1d(-np.inf, x))
plt.plot(x, cdf(x))
Integrating between 0 and x you get the same you are seeing now (to the right of 0), but that's not a cdf at all:
wrong_cdf = np.vectorize(lambda x: ag.integrate_box_1d(0, x))
plt.plot(x, wrong_cdf(x))
Not sure about why your function is not working exactly but one way of calculating CDF is as follows:
def get_cdf_1(data):
# start with sorted list of data
x = [i for i in sorted(data)]
cdf = []
for xs in x:
# get the sum of the values less than each data point and store that value
# this is normalised by the sum of all values
cum_val = sum([i for i in data if i <= xs])/sum(data)
cdf.append(cum_val)
return x, cdf
There is no doubt a faster way of computing this using numpy arrays rather than appending values to a list, but this returns values in the same format as your original example.
I think it's just:
def get_cdf(data):
return sorted(data), np.linspace(0, 1, len(data))
but I might be misinterpreting the question!
when I compare this to the analytic result I get the same:
x_cdf, y_cdf = get_cdf(st.pareto.rvs(1, size=10000))
import matplotlib.pyplot as plt
plt.semilogx(x_cdf, y_cdf)
plt.semilogx(x_cdf, st.pareto.cdf(x_cdf, 1))

Python: While loop - how do I avoid division by zero?

I am writing code for summing the Fourier Series that ranges from [-n,n]. However, I'm having trouble with it iterating when it gets to n = 0. I wrote an 'if' statement inside my while loop so it can ignore it, but it seems like it isn't. Here's my code:
from __future__ import division
import numpy as np
import math
import matplotlib.pyplot as plt
#initial values
ni = -10
nf = 10
ti = -3
tf = 3
dt = 0.01
yi = 0 #initial f(t) value
j = complex(0,1)
#initialization
tarray = [ti]
yarray = [yi]
t = ti
n = ni
y = yi
cn = 1/(8*(np.pi)**3*n**3*j**3)*(j*4*np.pi*n) #part (b)
#iterating loop
while t<tf:
n = ni
y = yi
while n<nf:
if n == 0:
cn = 1/6
y += cn
n += 1
else:
y += cn*np.exp(j*np.pi*n*t)
n += 1
yarray.append(y)
t+=dt
tarray.append(t)
#converting list-array
tarray = np.array(tarray)
yarray = np.array(yarray)
#plotting
plt.plot(tarray,yarray, linewidth = 1)
plt.axis("tight")
plt.xlabel('t')
plt.ylabel('f(t) upto n partial sums')
plt.title('Fourier Series for n terms')
plt.legend()
plt.show()
I want it to iterate and create an array of y-values for n ranging from some negative number to some positive number (say for n from [-10,10]), but as soon as it hits n = 0 it seems to be plugging that in into the 'else' clause even though I want it to use what's in the 'if' clause, giving me a "ZeroDivisionError: complex division by zero". How do I fix this?
Edit: Put the entire code block here so you can see the context.
This is not the most elegant way at all but try this:
while t<tf:
n = ni
y = yi
while n<nf:
try:
1/n
cn = 1/6
y += cn
n += 1
except ZeroDivisionError:
y += cn*np.exp(j*np.pi*n*t) #1/n*np.sin(n*t)
n += 1
yarray.append(y)
t+=dt
tarray.append(t)
The coefficient cn is a function of n and should be updated in every loop. You made it constant (and even equal to 1/6 for positive n).
The inner loop could look like
y = 1/6 # starting with n = 0
for n in range(1,nf):
y -= 1/(2*np.pi*n)**2 * np.sin(np.pi*n*t) # see below
Corresponding coefficients for positive and negative n's are equal and exp(ix) - exp(-ix) = 2i sin(x), so it nicely reduces. (Double check the calculation.)

defining integral using trapezoidal rule(beginner)

My programm aims in defining the integral of a given function between two numbers (x1,x2),using n trapezoids.As it seems,my department's auto evaluating programm gives different answers than the ones of mine.Problem is that i cant find anything wrong in my code...
def funct(x):
val= -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
return val
x1,x2,n=input()
Dx=float(x2-x1)/n
Sum=0
i=x1+Dx
while i<x2:
val=funct(i)
Sum+=val
i+=Dx
Sum=2*Sum
val1=funct(x1)
val2=funct(x2)
S=(Dx/2)*(val1+val2+Sum)
print "%.3f" %S
Due to rounding issues, your while cycle always includes last value of x, try using exact integer arithmetic
x0, x1 = -88.787529, 83.494648
n = 1942
dx = (x1-x0)/n
s = 0
i = 1
while i < n:
# if we allow i == n, in the following row we'll have
# x0 + n*dx = x0 + n * (x1-x0) / n = x0 + x1 - x0 = x1
# but we want to exclude the last term
s = s + funct(x0+i*dx)
i = i + 1
result = (s + funct(x0)/2.0 + funct(x1)/2.0)*dx
I know this is probably some sort of homework question, but in general, don't reinvent the wheel:
import numpy
def funct(x):
return -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
x1, x2 = -88.787529, 83.494648
n = 1942
# n "panels", n+1 points
x = numpy.linspace(x1, x2, n+1)
y = funct(x)
result = numpy.trapz(y, x)

Assigning input markers to function output in python

Sorry for the seemingly elementary question. What I'm trying to implement is summarized in the following steps:
Generate input variables: x, y.
Let z = F(x,y).
Plot z's for particular combinations of x and y.
For example:
zlist = []
for _ in range(100):
x = np.random.random()*1.
y = np.random.random()*.5
if x < .5:
z = y / 2
else:
z = y * 2
zlist.append(z)
Now if I want to plot z for all the x between (0, 0.3), I presumably would need some marker on each element in zlist indicating its inputs variables. How would I attach such marker and then access it from the list when plotting?
I don't actually know anything about Numpy, so someone please comment and tell me if I'm making a fool out of myself. It seems like vanilla python behavior, though.
Rather than appending z, let's append (z,x) instead. Now zlist is a list of tuples, and you can loop through and plot by checking zlist[i][1].
zlist = []
for _ in range(100):
x = np.random.random()*1.
y = np.random.random()*.5
if x < .5:
z = y / 2
else:
z = y * 2
zlist.append((z,x))
for value in zlist:
if value[1] > 0 and value[1] < 0.3:
# Plot value[0]
# Or if you prefer list comprehensions:
# [value[0] for value in zlist if value[1] >0 and value[1] < 0.3]
# that will return a list with only the z values in zlist.
With numpy it's almost always much more efficient to perform operations on vectors and
arrays rather than on built-in Python sequence types such as lists. Here's one
way you can quickly find F(x, y) for every combination of two sets of random x
and y values without looping in Python. The result is going to be an nx-by-ny
array Z, where Z[i, j] = F(x[i], y[j]).
First of all, you can generate all of your x, y inputs as vectors:
nx = 100
ny = 200
x = np.random.random(size=nx) * 1.
y = np.random.random(size=ny) * 5.
For the result to be an nx-by-ny array, you could take these two vectors and
multiply them by ones to get two 2D nx-by-ny arrays containing the x and y
values in the rows and columns respectively. You can do this by taking advantage of numpy's
broadcasting rules:
x_arr = x[:,np.newaxis] * np.ones((nx,ny))
y_arr = y[np.newaxis,:] * np.ones((nx,ny))
The function you will apply to each x,y pair depends on the x value.
Fortunately, you can use np.where(<condition>, <do_this>, <do_that>) to apply
different operations to the values in your input depending on some condition:
Z = np.where(x_arr < 0.5, y_arr / 2., y_arr * 2.)
We can check that all the results are correct:
for i in xrange(nx):
for j in xrange(ny):
if x[i] < 0.5:
assert Z[i, j] == y[j] / 2.
else:
assert Z[i, j] == y[j] * 2
There's actually an even cleaner way to compute Z without expanding x and y into 2D arrays. Using the same broadcasting trick we used to get
x_arr and y_arr, you can pass x and y directly to np.where():
x2 = x[:,np.newaxis]
y2 = y[np.newaxis,:]
Z2 = np.where(x2 < 0.5, y2 / 2., y2 * 2.)
assert np.all(Z == Z2)

Categories

Resources