Minkowsky distances calculated with linalg.norm taking unusual time - python-3.x

This is part of my implementation of the K-medoids algorithm. I tested the algorithm with small images that I'm generating randomly and works fine (6X6). The problem comes when I use a real image (620x412), the algorithm is still converging but is taking approximately 5 minutes per iteration. After profiling my code, I detected that np.linalg.norm is causing the bottleneck, but I'm not sure what I'm doing wrong here
Call count Time(ms) Own Time(ms)
<method 'reduce' of 'numpy.ufunc' objects> 88329 70672 70672
norm 44164 152196 46999
<method 'astype' of 'numpy.ndarray' objects> 44165 38445 38445
manhattan_distance 44159 199809 37795
<built-in method numpy.core._multiarray_umath.implement_array_function> 88334 166973 9512
update_medoids 1 103862 658
This is my implementation of update_medoids and manhattan distance
def manhattan_distance(pixels, medoids):
"""
:param pixels: Array of RGB pixels
:param medoids: pixels selected as medoids. It can be a (3,) array (single medoid), or a vector (k, 3) for
multiple medoidss
:return:
"""
if len(medoids.shape) == 1:
medoids = medoids.reshape(1, len(medoids))
distance = np.linalg.norm(pixels - medoids, ord=1, axis=1)
else:
distance = np.zeros((pixels.shape[0], len(medoids)))
for medoid_idx in range(len(medoids)):
medoid = medoids[medoid_idx].reshape(1, len(medoids[medoid_idx]))
distance[:, medoid_idx] = np.linalg.norm(pixels - medoid, ord=1, axis=1)
return distance
update medoids function:
def update_medoids(pixels, medoids, distance):
'''
:param pixels: Array of RGB pixels
:param medoids: vector (k, 3) of pixels selected as medoids.
:param distance: distance function used in algorithm
:return: new vector of medoids with swapped members, if any.
'''
distances = distance(pixels, medoids)
labels = assign_labels(distances)
new_medoids = medoids
for cluster in set(labels):
cluster_dissimilarity = np.sum(distance(pixels, medoids[cluster]))
cluster_points = pixels[labels == cluster]
for data_point in cluster_points:
hypothesis_medoid = data_point
temp_cluster_dissimilarity = np.sum(distance(pixels, hypothesis_medoid))
if temp_cluster_dissimilarity < cluster_dissimilarity:
cluster_dissimilarity = temp_cluster_dissimilarity
new_medoids[cluster] = hypothesis_medoid
return new_medoids
My suspicion is in np.linalg.norm(pixels - medoid, ord=1, axis=1) but my only guess is that broadcasting is slowing down the calculation, although that doesn't sound realistic. thoughts?
EDIT
input samples
pixels is a vector of pixels that is obtained by reshaping the matrix representation of an image, that is
[[[232 10 22] [213 76 156] [156 232 103]]
[[116 160 12] [115 188 118] [ 74 42 106]]]
[[157 30 36] [ 98 89 173] [142 76 225]]]
is reshaped into a vector that looks like this
[[232 10 22]
[213 76 156]
[156 232 103]
[116 160 12]
[115 188 118]
[ 74 42 106]
[157 30 36]
[ 98 89 173]
[142 76 225]]
medoids is a subset of pixels and act as representatives of each cluster.

Related

Overlay of two plots from two different data sources using Python / hvplot

I would like to plot a line plot (source: pandas dataframe) over a hvplot (source: xarray/ NetCDF).
The xarray looks like this:
dataDIR = 'ceilodata.nc'
DS = xr.open_dataset(dataDIR)
DS = DS.transpose()
print(DS)
<xarray.Dataset>
Dimensions: (range_hr: 32, range: 1024, layer: 3, time: 5760)
Coordinates:
* range_hr (range_hr) float32 0.001 4.995 9.99 ... 144.9 149.9 154.8
* range (range) float32 14.98 29.97 44.96 ... 1.533e+04 1.534e+04
* layer (layer) int32 1 2 3
* time (time) datetime64[ns] 2022-03-18 ... 2022-03-18T23:59:46
Data variables: (12/41)
zenith float32 ...
wavelength float32 ...
scaling float32 ...
range_gate_hr float32 ...
range_gate float32 ...
longitude float32 ...
... ...
cbe (layer, time) int16 ...
beta_raw_hr (range_hr, time) float32 ...
beta_raw (range, time) float32 ...
bcc (time) int8 ...
base (time) float32 ...
average_time (time) int32 ...
Attributes: (12/13)
comment:
software_version: 15.06.1 2.13 1.040 1
title: CHM15k Nimbus
wmo_id: 10865
month: 3
source: CHM160138
... ...
serlom: TUB160038
location: muenchen
year: 2022
device_name: CHM160138
institution: DWD
day: 18
The pandas dataframe source looks like this:
df = pd.read_csv('PTU.csv')
print(df)
Unnamed: 0 PTU
0 2022-03-18 07:38:56 451.839
1 2022-03-18 07:38:57 468.826
2 2022-03-18 07:38:58 469.093
3 2022-03-18 07:38:59 469.356
4 2022-03-18 07:39:00 469.623
... ... ...
6140 2022-03-18 09:21:16 31690.600
6141 2022-03-18 09:21:17 31694.700
6142 2022-03-18 09:21:18 31692.900
6143 2022-03-18 09:21:19 31712.000
6144 2022-03-18 09:21:20 31711.500
[6145 rows x 2 columns]
Both are time dependend datasets but have different time stamps and frequencies. Time is index in each data set.
I tried to plot them together with additional imports of holoviews. While each single plot is no problem, plotting them together seems not to work the way I tried it:
import hvplot.pandas
import holoviews as hv
# cmap of the xarray:
ceilo = (DS.b_r.hvplot(cmap="viridis_r", width = 850, height = 600, title = 'title', clim = (5, 80))
# line plot of the data frame
p = df.hvplot.line()
# add pressure line plot to pcolormeshplot using * which overlays the line on the plot
ceilo * p
but this ended in an error message with the following complete traceback:
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-10-2b1c6baca339> in <module>
24 p = df.hvplot.line()
25 # add pressure line plot to pcolormeshplot using * which overlays the line on the plot
---> 26 ceilo * df
c:\python38\lib\site-packages\pandas\core\ops\common.py in new_method(self, other)
68 other = item_from_zerodim(other)
69
---> 70 return method(self, other)
71
72 return new_method
c:\python38\lib\site-packages\pandas\core\arraylike.py in __rmul__(self, other)
118 #unpack_zerodim_and_defer("__rmul__")
119 def __rmul__(self, other):
--> 120 return self._arith_method(other, roperator.rmul)
121
122 #unpack_zerodim_and_defer("__truediv__")
c:\python38\lib\site-packages\pandas\core\frame.py in _arith_method(self, other, op)
6936 other = ops.maybe_prepare_scalar_for_op(other, (self.shape[axis],))
6937
-> 6938 self, other = ops.align_method_FRAME(self, other, axis, flex=True, level=None)
6939
6940 new_data = self._dispatch_frame_op(other, op, axis=axis)
c:\python38\lib\site-packages\pandas\core\ops\__init__.py in align_method_FRAME(left, right, axis, flex, level)
275 elif is_list_like(right) and not isinstance(right, (ABCSeries, ABCDataFrame)):
276 # GH 36702. Raise when attempting arithmetic with list of array-like.
--> 277 if any(is_array_like(el) for el in right):
278 raise ValueError(
279 f"Unable to coerce list of {type(right[0])} to Series/DataFrame"
c:\python38\lib\site-packages\holoviews\core\element.py in __iter__(self)
94 def __iter__(self):
95 "Disable iterator interface."
---> 96 raise NotImplementedError('Iteration on Elements is not supported.')
97
98
NotImplementedError: Iteration on Elements is not supported.
Is the different time frequency a problem here? The line plot should be orientated along the x- and the y-axis considering the right time stamp and altitude of the underlying cmap-(matplotlib)-plot.
To illustrate what I am aiming for, here is a picture of my goal:
Thanks for reading / helping.
I found a solution for this case:
Both dataset time columns have to have the same format. In my case it's: datetime64[ns] (to adopt to the NetCDF xarray). That is why I converted the dataframe time column to datetime64[ns]:
df.Datetime = df.Datetime.astype('datetime64')
Also I found the data to be type "object". So I transformed it to "float":
df.PTU = df.PTU.astype(float) # convert to correct data type
The last step was choosing hvplot as this helps in plotting xarray data
import hvplot.xarray
hvplot.quadmesh
And here is my final solution:
title = ('Ceilo data + '\ndate: '+ str(DS.year) + '-' + str(DS.month) + '-' + str(DS.day))
ceilo = (DS.br.hvplot.quadmesh(cmap="viridis_r", width = 850, height = 600, title = title,
clim = (1000, 10000), # set colorbar limits
cnorm = ('log'), # choose log scale
clabel = ('colorbar title'),
rot = 0 # degree rotation of ticks
)
)
# from: https://justinbois.github.io/bootcamp/2020/lessons/l27_holoviews.html
# take care! may take 2...3 minutes to be ploted:
p = hv.Points(data=df,
kdims=['Datetime', 'PTU'],
).opts(#alpha=0.7,
color='red',
size=1,
ylim=(0, 5000))
# add PTU line plot to quadmesh plot using * which overlays the line on the plot
ceilo * p

Pytorch: RGB value ranges 0-1 after rescaling, How do I normalize images?

I wrote a class to rescale images, but the RGB value became ranging from 0 to 1 after preocessing. What happened to the RGB which intuitively should be ranging from 0-255 ? Following are the Rescale class and the RGB values after rescaling.
Question:
Do I still need a Min-Max Normalization, map the RGB value to 0-1?
How do I apply transforms.Normalization, where do I put the Normalization, before or after the Rescale, how do I calculate the mean and variance, use the RGB value ranging from 0-255 or 0-1?
Thanks for your time!
class Rescale(object):
def __init__(self, output_size):
assert isinstance(output_size, (int, tuple))
self.output_size = output_size
def __call__(self, sample):
image, anno = sample['image'], sample['anno']
# get orginal width and height of image
h, w = image.shape[0:2]
# if output_size is an integer
if isinstance(self.output_size, int):
if h > w:
new_h, new_w = h * self.output_size / w, self.output_size
else:
new_h, new_w = self.output_size / h, w * self.output_size / h
# if output size is a tuple (a, b)
else:
new_h, new_w = self.output_size
new_h, new_w = int(new_h), int(new_w)
image = transform.resize(image, (new_h, new_w))
return {'image': image, 'anno': anno}
[[[0.67264216 0.50980392 0.34503034]
[0.67243905 0.51208121 0.34528431]
[0.66719145 0.51817184 0.3459951 ]
...
[0.23645098 0.2654311 0.3759458 ]
[0.24476471 0.28003857 0.38963938]
[0.24885877 0.28807445 0.40935877]]
[[0.67465196 0.50994608 0.3452402 ]
[0.68067157 0.52031373 0.3531848 ]
[0.67603922 0.52732436 0.35839216]
...
[0.23458333 0.25195098 0.36822142]
[0.2461343 0.26886127 0.38314558]
[0.2454384 0.27233056 0.39977664]]
[[0.67707843 0.51237255 0.34766667]
[0.68235294 0.5219951 0.35553024]
[0.67772059 0.52747687 0.35659176]
...
[0.24485294 0.24514568 0.36592999]
[0.25407436 0.26205475 0.38063318]
[0.2597007 0.27202914 0.40214216]]
...
[[[172 130 88]
[172 130 88]
[172 130 88]
...
[ 63 74 102]
[ 65 76 106]
[ 67 77 112]]
[[173 131 89]
[173 131 89]
[173 131 89]
...
[ 65 74 103]
[ 64 75 105]
[ 63 73 108]]
[[173 131 89]
[174 132 90]
[174 132 90]
...
[ 63 72 101]
[ 62 71 102]
[ 61 69 105]]
...
You can use torchvision to accomplish this.
transform = transforms.Compose([
transforms.Resize(output_size),
transforms.ToTensor(),
])
This requires a PIL image as input. It will return the tensor in [0, 1] range.You may also add mean-standard normalization as below
transform = transforms.Compose([
transforms.Resize(output_size),
transforms.ToTensor(),
transforms.Normalize(mean, std),
])
Here mean and std are per channel mean and standard deviation of all pixels of all images in the training set. You need to calculate them after resizing all images and converting to torch Tensor. One way to do this would be to apply first two transformation (resize and ToTensor) and then calculate mean and std over all training images like this
x = torch.concatenate([train_data[i] for i in range(len(train_data))])
mean = torch.mean(x, dim=(0, 1))
std = torch.std(x, dim=(0, 1))
Then you use this mean and std value with Normalize transorm above.

Getting spectrogram from recorded audio , ERROR: "ParameterError: Audio buffer is not finite everywhere"

I'm trying to record a sound using 'pyaudio' and get a spectrogram for the audio, but I get the above error: " Audio buffer is not finite everywhere".
It might be a possible duplicate, but I didn't find something which solves the eroror. Here is my code:
CHUNK = 96000 # number of data points to read at a time
RATE = 16000 # time resolution of the recording device (Hz)
p=pyaudio.PyAudio() # start the PyAudio class
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK) #uses default input device
# create a numpy array holding a single read of audio data
stop=0
while not stop: #to it a few times just to see
print('Recording')
audio=np.frombuffer(stream.read(CHUNK))
print(type(audio[0]))
print("max value: ",np.max(audio))
print("min value: ",np.min(audio))
sd.play(audio,RATE)
S = librosa.feature.melspectrogram(audio, sr=RATE)
S = 10 * np.log(S + 1e-15)
#em=get_emotion_audio(audio,RATE)
#print("[DETECTED] ",em)
stop=1
# close the stream gracefully
stream.stop_stream()
stream.close()
p.terminate()
Here is the error I'am getting:
'''
Recording
<class 'numpy.float64'>
max value: nan
min value: nan
---------------------------------------------------------------------------
ParameterError Traceback (most recent call last)
<ipython-input-3-33fa263f625d> in <module>
19 print("min value: ",np.min(audio))
20 sd.play(audio,RATE)
---> 21 S = librosa.feature.melspectrogram(audio, sr=RATE)
22 S = 10 * np.log(S + 1e-15)
23 #em=get_emotion_audio(audio,RATE)
~\Anaconda3\lib\site-packages\librosa\feature\spectral.py in melspectrogram(y, sr, S, n_fft, hop_length, power, **kwargs)
1529
1530 S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length,
-> 1531 power=power)
1532
1533 # Build a Mel filter
~\Anaconda3\lib\site-packages\librosa\core\spectrum.py in _spectrogram(y, S, n_fft, hop_length, power)
1555 else:
1556 # Otherwise, compute a magnitude spectrogram from input
-> 1557 S = np.abs(stft(y, n_fft=n_fft, hop_length=hop_length))**power
1558
1559 return S, n_fft
~\Anaconda3\lib\site-packages\librosa\core\spectrum.py in stft(y, n_fft, hop_length, win_length, window, center, dtype, pad_mode)
159
160 # Check audio is valid
--> 161 util.valid_audio(y)
162
163 # Pad the time series so that frames are centered
~\Anaconda3\lib\site-packages\librosa\util\utils.py in valid_audio(y, mono)
168
169 if not np.isfinite(y).all():
--> 170 raise ParameterError('Audio buffer is not finite everywhere')
171
172 return True
ParameterError: Audio buffer is not finite everywhere
'''
The solution was to change the two lines as:
audio=np.frombuffer(stream.read(CHUNK),dtype=np.int16)
S = librosa.feature.melspectrogram(audio.astype('float32'), sr=RATE)

Graph coloring with CVXPY set up constraints

I am trying to code the constraints for the graph coloring problem using CVXPY. I am pretty new to mixed-integer programming (MIP), and I am having some difficulty specifying the constraints. I have input data like the “edges” list below. Where each tuple in the list is an edge that starts on one node and ends on the other. For example the first edge starts on node “0” and ends on node “1”.
The constraints I would like to specify are:
each node can have only one color.
vertices sharing one edge should have different colors.
each node must have at least one color.
The objective function would be the number of colors used.
For a selection variable I want to specify the color each node takes.
I’m using the colors array to multiply with the selection variable and then sum for each node, to select the color for the node and specify that each node can only have one color.
I’m getting the error below. Am I constructing the selection variable correctly?
Also this seems like a lot of work, does anyone see a simpler way to do this? Or does anyone know of an example of solving the graph coloring problem with CVXPY?
One more thing, if I transpose the colors array the error goes away.
Input data:
edges
[(0, 1), (1, 2), (1, 3)]
code:
# selection variable
# 4 is the number of nodes
selection = cvxpy.Variable(4, boolean=True)
# array for colors
colors = np.array([[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1],
[1,1,0,0],
[1,1,1,0],
[1,1,1,1],
[0,1,1,1],
[0,0,1,1],
[1,0,1,0],
[0,1,0,1],
[0,1,1,0],
[1,1,0,0],
[0,0,0,0]])
# each node can only have one color constraint
one_color = cvxpy.sum(selection * colors, axis=0) == 1
error:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-b22226c89a2f> in <module>()
1 # each node can only have one color constraint
2
----> 3 one_color = cvxpy.sum(selection * colors, axis=0) == 1
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/expressions/expression.py in cast_op(self, other)
47 """
48 other = self.cast_to_const(other)
---> 49 return binary_op(self, other)
50 return cast_op
51
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/expressions/expression.py in __mul__(self, other)
385 return cvxtypes.multiply_expr()(self, other)
386 elif self.is_constant() or other.is_constant():
--> 387 return cvxtypes.mul_expr()(self, other)
388 else:
389 warnings.warn("Forming a nonconvex expression.")
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/atoms/affine/binary_operators.py in __init__(self, lh_exp, rh_exp)
41
42 def __init__(self, lh_exp, rh_exp):
---> 43 super(BinaryOperator, self).__init__(lh_exp, rh_exp)
44
45 def name(self):
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/atoms/atom.py in __init__(self, *args)
42 self.args = [Atom.cast_to_const(arg) for arg in args]
43 self.validate_arguments()
---> 44 self._shape = self.shape_from_args()
45 if len(self._shape) > 2:
46 raise ValueError("Atoms must be at most 2D.")
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/atoms/affine/binary_operators.py in shape_from_args(self)
107 """Returns the (row, col) shape of the expression.
108 """
--> 109 return u.shape.mul_shapes(self.args[0].shape, self.args[1].shape)
110
111 def is_atom_convex(self):
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/utilities/shape.py in mul_shapes(lh_shape, rh_shape)
140 lh_old = lh_shape
141 rh_old = rh_shape
--> 142 lh_shape, rh_shape, shape = mul_shapes_promote(lh_shape, rh_shape)
143 if lh_shape != lh_old:
144 shape = shape[1:]
~/anaconda2/envs/py36/lib/python3.6/site-packages/cvxpy/utilities/shape.py in mul_shapes_promote(lh_shape, rh_shape)
107 if lh_mat_shape[1] != rh_mat_shape[0]:
108 raise ValueError("Incompatible dimensions %s %s" % (
--> 109 lh_shape, rh_shape))
110 if lh_shape[:-2] != rh_shape[:-2]:
111 raise ValueError("Incompatible dimensions %s %s" % (
ValueError: Incompatible dimensions (1, 4) (14, 4)

Difference in use of ** and pow function

while attempting to write a cost function for linear regression the error is arising while replacing ** with pow function in cost_function :
Original cost function
def cost_function(x,y,theta):
m = np.size(y)
j = (1/(2*m))*np.sum(np.power(np.matmul(x,theta)-y),2)
return j
Cost function giving the error:
def cost_function(x,y,theta):
m = np.size(y)
j = (1/(2*m))*np.sum((np.matmul(x,theta)-y)**2)
return j
Gradient Descent
def gradient_descent(x,y,theta,learn_rate,iters):
x = np.mat(x);y = np.mat(y); theta= np.mat(theta);
m = np.size(y)
j_hist = np.zeros(iters)
for i in range(0,iters):
temp = theta - (learn_rate/m)*(x.T*(x*theta-y))
theta = temp
j_hist[i] = cost_function(x,y,theta)
return (theta),j_hist
Variable values
theta = np.zeros((2,1))
learn_rate = 0.01
iters = 1000
x is (97,2) matrix
y is (97,1) matrix
cost function is calculated fine with value of 32.0727
The error arises while using the same function in gradient descent.
The error am getting is LinAlgError: Last 2 dimensions of the array must be square
First let's distinguish between pow, ** and np.power. pow is the Python function, that according to docs is equivalent to ** when used with 2 arguments.
Second, you apply np.mat to the arrays, making np.matrix objects. According to its docs:
It has certain special operators, such as *
(matrix multiplication) and ** (matrix power).
matrix power:
In [475]: np.mat([[1,2],[3,4]])**2
Out[475]:
matrix([[ 7, 10],
[15, 22]])
Elementwise square:
In [476]: np.array([[1,2],[3,4]])**2
Out[476]:
array([[ 1, 4],
[ 9, 16]])
In [477]: np.power(np.mat([[1,2],[3,4]]),2)
Out[477]:
matrix([[ 1, 4],
[ 9, 16]])
Matrix power:
In [478]: arr = np.array([[1,2],[3,4]])
In [479]: arr#arr # np.matmul
Out[479]:
array([[ 7, 10],
[15, 22]])
With a non-square matrix:
In [480]: np.power(np.mat([[1,2]]),2)
Out[480]: matrix([[1, 4]]) # elementwise
Attempting to do matrix_power on a non-square matrix:
In [481]: np.mat([[1,2]])**2
---------------------------------------------------------------------------
LinAlgError Traceback (most recent call last)
<ipython-input-481-18e19d5a9d6c> in <module>()
----> 1 np.mat([[1,2]])**2
/usr/local/lib/python3.6/dist-packages/numpy/matrixlib/defmatrix.py in __pow__(self, other)
226
227 def __pow__(self, other):
--> 228 return matrix_power(self, other)
229
230 def __ipow__(self, other):
/usr/local/lib/python3.6/dist-packages/numpy/linalg/linalg.py in matrix_power(a, n)
600 a = asanyarray(a)
601 _assertRankAtLeast2(a)
--> 602 _assertNdSquareness(a)
603
604 try:
/usr/local/lib/python3.6/dist-packages/numpy/linalg/linalg.py in _assertNdSquareness(*arrays)
213 m, n = a.shape[-2:]
214 if m != n:
--> 215 raise LinAlgError('Last 2 dimensions of the array must be square')
216
217 def _assertFinite(*arrays):
LinAlgError: Last 2 dimensions of the array must be square
Note that the whole traceback lists matrix_power. That's why we often ask to see the whole traceback.
Why are you setting x,y and theta to np.mat? The cost_function uses matmul. With that function, and its # operator, there are few(er) good reasons for using np.matrix.
Despite the subject line, you did not try to use pow. That confused me and at least one other commentator. I tried to find a np.pow or a scipy version.

Resources