Building table with specifik data - matlab

I need some help with a task that I have:
I have 4 vectors with data: 3 of them are with dates and the 4th one is with overdue days, something like this:
dateAdded dueDate date overdue
Published
02/11/18 02/11/18 03/11/18 1
03/11/18 04/11/18 11/11/18 7
03/11/18 04/11/18 04/12/18 30
04/11/18 05/11/18 ongoing overdue up to today
Can you give me some tips how can I create a table with the overdue days for each month from the year, considering that when I have transition from one month to another one I have to count the overdue to both months? Also when the datePublished hasn't come yet I have to count the overdue dates for each month passed.
Thanks

My solution:
number_months = max(((year(dateAdded)-2018))*12 + rem(month(dateAdded),13));
idx = 1;
ii=1;
for k=1:number_months
kpit(k,1) = k;
kpit(k,2) = 0;
kpit(k,3) = 0;
end
for i=1:data_length_Added
% if month(dateAdded(i)) == month(dueDate(i)) && month(dateAdded(i)) ~= 0
if month(dueDate(i)) == month(datePublished(i)) && month(dateAdded(i)) ~= 0
[~,idx]=ismember(month(dueDate(i)),kpit(:,1),'rows');% finds the position of an element from the array in the array for months
kpit(idx,2) =kpit(idx,2) + overdue(i);
kpit(idx,3) = kpit(idx,3) + 1;
idx = idx + 1;
else if month(datePublished(i)) == month(dueDate(i)) + 1
[~,idx]=ismember(month(dueDate(i)),kpit(:,1),'rows');
[~,idx1]=ismember(month(datePublished(i)),kpit(:,1),'rows');
year1 = year(datePublished(i));
weight = (day(datePublished(i)))/eomday(year1,month(datePublished(i)));
kpit(idx,2) =kpit(idx,2) + overdue(i);
kpit(idx1,2) =kpit(idx1,2) + overdue(i)*weight;
kpit(idx,3) = kpit(idx,3)+ 1;
kpit(idx1,3) = kpit(idx1,3)+ 1;
if (month(datePublished(i)) ~= 0 && month(datePublished(i)) > month(dueDate(i))+1)
% if (datePublished > dueDate)% If the correction is done check every month if it is the next one
[~,idx]=ismember(month(datePublished(i)),kpit(:,1),'rows');
year1 = year(datePublished(i));
weight = day(datePublished(i))/eomday(year1,month(datePublished(i))); %Should count all overdue days for full months and weighted overdue dats for not full months
kpit(idx,2) = overdue(i)*weight;
kpit(idx,3) = kpit(idx,3) + 1;
for j=(month(datePublished(i))-1):month(dueDate(i))
[~,idx]=ismember(month(datePublished(j)),kpit(:,1),'rows');
kpit(idx,2) =kpit(idx,2) + overdue(j);
kpit(idx,3) = kpit(idx,3)+ 1;
j = j +1;
end
end
end
end
else if month(dueDate(i)) == 0
[~,idx]=ismember(month(today),kpit(:,1),'rows');
year1 = year(today);
weight = day(today)/eomday(year1,month(today)); %Should count all overdue days for full months and weighted overdue dats for not full months
kpit(idx,2) = overdue(i)*weight;
kpit(idx,3) = kpit(idx,3) + 1;
for j=(month(today)-1):month(dueDate(i))
[~,idx]=ismember(month(today),kpit(:,1),'rows');
kpit(idx,2) =kpit(idx,2) + overdue(j);
kpit(idx,3) = kpit(idx,3)+ 1;
j = j +1;
end
end
end

Related

Switch function not doing what I want

I wrote a simple program to help evaluate a probability problem. During 10 hours of the day, the probability of a certain event is different than for the rest of the day. To account for this , i'm trying to use the switch function but it's not working. The code is the following (I'm using MATLAB):
clear all
status = 0; %0 ventilador apagat, 1 encès.
nsim = 10000;
enceses = 0;
runtime = 0;
sampletime = 0;
minute = 0;
while (runtime < 10000 || enceses < 18000)
r = rand;
switch minute
case minute < 601
if (r < 0.1642)
status = 0;
else
runtime = runtime + 5/60;
if status == 0
status = 1;
enceses = enceses + 1;
else
end
end
sampletime = sampletime + 5/60;
minute = minute + 5;
case minute > 600
if (r < 0.801)
status = 0;
else
runtime = runtime + 5/60;
if status == 0
status = 1;
enceses = enceses + 1;
else
end
end
sampletime = sampletime + 5/60;
minute = minute + 5;
if minute == 1440
minute = 0;
end
end
end
enceses
runtime
sampletime
nsim does nothing for the moment
I analyzed the execution step by step and found that in the first loop the switch works as intended and goes into the first case but after that it enters neither, if i put an otherwise print ("error"), it just prints out a bunch of errors.
For your application, instead of switch-case, you can use if-elseif-end statements as follows:
if minute < 600
<some statements>
elseif minute >= 600
<another statements>
end

Iterate over a vector in matlab

So I'm working on a program. I need to iterate over a vector similar to this sample = [0; 0; 0; 1; 1; 1 ; 0]. I was thinking about using loops with accumulators to build a new 2d array where column 1 is how many 0s or 1s appear and column 2 is for which token it is. But I'm new to the syntax of matlab and checking the docs i mostly see slicing. Any ideas about building the new matrix are welcome.
sample vector and output below
arr = [0; 0; 0; 1; 1; 1; 0];
tokenizeSignal(arr)
ans =
3 0
3 1
1 0
Proposed strategy (array contains only 1 and 0) :
Initialize 2 counters
count_0 = 0;
count_1 = 0;
Iterate over the whole array arr
arr = [0; 0; 0; 1; 1; 1; 0];
[n,m] = size(arr); %m is espected equal to 1
y = arr[1,1]; %first element of the array, we need a reference
Start the loop and read the current element
for i=1:n
x = arr[i,1];
start to count how many zeros or how many ones from the last group if the last element was zero or one
if (x == 0 && y == 0)
count_0 = count_0 + 1;
count_1 = 0;
else if (x == 1 && y == 1)
count_1 = count_1 + 1;
count_0 = 0;
end
print every time the value will change (last term of a "sequence")
if (x != arr[1,i+1] && count_1 > 0 && i<n)
print(count_1, '1');
else if (x != arr[1,i+1] && count_0 > 0 && i<n)
print(count_0, '0');
end
update the values and close the FOR loop
y = x;
end
out of the cycle, print the last time
if (count_1 > 0)
print(count_1, '1');
else if (count_0 >)
print(count_0, '0');
end
Of course you can change the print with store the values in a proper array.

Matlab code to analyze data on a grid

I have a point set with (x,y) coordinates and their corresponding weights in matrix a where the 1st, 2nd and 3rd columns are x, y, and weight respectively. I want to divide this point set into grid cells, and count the number of points in each grid and the total weight of each grid.
I tried the small example below, but it did not work. Here I tried to divide this data set into a 2x2 small grid and tried to count number of points and their sum of weights. Further, I have big data set, so I can not extend this approach further when I need different step sizes for grid.
Can someone please help me to develop an easier approach?
function dataTree
count=zeros(9,1);
avg=zeros(9,1);
data=[1 3 100; 2 1 120; 3 5 110; 4 2 100; 5 3 150; 6 2 100];
for i=1:6
if data(i,1)<=2
for j=1:6
if data(j,2)<=2
count(1) = count(1) + 1;
avg(1) = avg(1) + data(j,3);
elseif data(j,2)<=4
count(2) = count(2) + 1;
avg(2) = avg(2) + data(j,3);
elseif data(j,2)<=6
count(3) = count(3) + 1;
avg(3) = avg(3) + data(j,3);
end
end
elseif data(i,1)<=4
for j=1:6
if data(j,2)<=2
count(4) = count(4) + 1;
avg(4) = avg(4) + data(j,3);
elseif data(j,2)<=4
count(5) = count(5) + 1;
avg(5) = avg(5) + data(j,3);
elseif data(j,2)<=6
count(6) = count(6) + 1;
avg(6) = avg(6) + data(j,3);
end
end
elseif data(i,1)<=6
for j=1:6
if data(j,2)<=2
count(7) = count(7) + 1;
avg(7) = avg(7) + data(j,3);
elseif data(j,2)<=4
count(8) = count(8) + 1;
avg(8) = avg(8) + data(j,3);
elseif data(j,2)<=6
count(9) = count(9) + 1;
avg(9) = avg(9) + data(j,3);
end
end
end
end
count'
avg'
If your x and y are not yet rounded to some arbitrary units, do so first:
x = round((x - min(x))/edgelength+1);
this makes sure that you obtain grid with edgelength sized squares, which is indicated by non-zero integers. Do the same for y.
Then you can use either sparse or accumarray to get the total weight. sparse is faster, but is less wide applicable:
gridWeight = sparse(x,y,weight);
if you want to get average weights, add 1 for each entry and divide by that matrix:
NumEntries = sparse(x,y,1);
MeanWeights = gridWeight./NumEntries;
accumarray can do both of these operations in one go:
gridWeight = accumarray([x y],weight);
MeanWeights = accumarray([x y], weight,[],#mean); %//add ,[], 'issparse' for sparse matrix
Note that sparse is a sub-functionality of accumarary by setting accumarray=([i,j],val,[],#sum,[],'issparse'). The only function sparse can handle is #sum and it's sole fill-value is 0, whilst for accumarray other functions and values can be used.

Filter points using hist in matlab

I have a vector. I want to remove outliers. I got bin and no of values in that bin. I want to remove all points based on the number of elements in each bin.
Data:
d1 =[
360.471912914169
505.084636471948
514.39429429184
505.285068055647
536.321181755858
503.025854206322
534.304229816684
393.387035881967
396.497969729985
520.592172434431
421.284713703215
420.401106087984
537.05330275495
396.715779872694
514.39429429184
404.442344469518
476.846474245118
599.020867750031
429.163139144079
514.941744277933
445.426761656729
531.013596812737
374.977332648255
364.660115724218
538.306752697753
519.042387479096
1412.54699036882
405.571202133485
516.606049132218
2289.49623498271
378.228766753667
504.730621222846
358.715764917016
462.339366699398
512.429858614816
394.778786157514
366
498.760463549388
366.552861126468
355.37022947906
358.308526273099
376.745272034036
366.934599077274
536.0901883079
483.01740134285
508.975480745389
365.629593988233
536.368800360349
557.024236456548
366.776498701866
501.007025898839
330.686029339009
508.395475983019
429.563732174866
2224.68806802212
534.655786464525
518.711297351426
534.304229816684
514.941744277933
420.32368479542
367.129404978681
525.626188464768
388.329756778952
1251.30895065927
525.626188464768
412.313764019587
513.697381733643
506.675438520558
1517.71183364959
550.276294237722
543.359917550053
500.639590923451
395.129864728041];
Histogram computation:
[nelements,centers] = hist(d1);
nelements=55 13 0 0 1 1 1 0 0 2
I want to remove all points apearing less than 5 (in nelements). It means only first 2 elements in nelements( 55, 13 ) remains.
Is there any function in matlab.
You can do it along these lines:
threshold = 5;
bin_halfwidth = (centers(2)-centers(1))/2;
keep = ~any(abs(bsxfun(#minus, d1, centers(nelements<threshold))) < bin_halfwidth , 2);
d1_keep = d1(keep);
Does this do what you want?
binwidth = centers(2)-centers(1);
centersOfRemainingBins = centers(nelements>5);
remainingvals = false(length(d1),1);
for ii = 1:length(centersOfRemainingBins )
remainingvals = remainingvals | (d1>centersOfRemainingBins (ii)-binwidth/2 & d1<centersOfRemainingBins (ii)+binwidth/2);
end
d_out = d1(remainingvals);
I don't know Matlab function for this problem, but I think, that function with follow code is what are you looking for:
sizeData = size(data);
function filter_hist = filter_hist(data, binCountRemove)
if or(max(sizeData) == 0, binCountRemove < 1)
disp('Error input!');
filter_hist = [];
return;
end
[n, c] = hist(data);
sizeN = size(n);
intervalSize = c(2) - c(1);
if sizeData(1) > sizeData(2)
temp = transpose(data);
else
temp = data;
end
for i = 1:1:max(sizeN)
if n(i) < binCountRemove
a = c(i) - intervalSize / 2;
b = c(i) + intervalSize / 2;
sizeTemp = size(temp);
removeInds = [];
k = 0;
for j = 1:1:max(sizeTemp)
if and(temp(j) > a, less_equal(temp(j), b) == 1)
k = k + 1;
removeInds(k) = j;
end
end
temp(removeInds) = [];
end
end
filter_hist = transpose(temp);
%Determines when 'a' less or equal to 'b' by accuracy
function less_equal = less_equal(a, b)
delta = 10^-6; %Accuracy
if a < b
less_equal = 1;
return;
end
if abs(b - a) < delta
less_equal = 1;
return;
end
less_equal = 0;
You can do something like this
nelements=nelements((nelements >5))

How to distribute values randomly over a given time period?

I am trying to distribute a certain value over a random period of time. To clarify more ,
Suppose I want to distribute product x and y over 30 days. I have 1500 items of product x that has to be distributed over 30 days randomly. There is a restriction on the number of items that can be distributed over 1 day i.e.max 60.
I have been trying to scratch out something but am really unsucessful with this problem. I am really new to programming so it would be a real help if somebody could point me to the right approach.
As an addendum, if I have more than 1 items to be distributed (like suppose there are x,y and z) with different values (ex. 1500, 1000, 900) and there is a limitation on how many items can be distributed on a particular day (max 150 per day) will this logic still work or should I look at something new. Also, should there be a check, like suppose 100 of x, 20 of y and 30 of z are distributed, then subtract the value (for the next day I have 1400 of x, 980 of y and 870 of z available for distribution) as this will change the permutation values ?
Thank you guys !
This should work for you!
days = 30;
elem = 1500;
max_x = 60;
x = randi(max_x,days,1);
remain = elem - sum(x);
while remain > 0
idx_1 = find(x < max_x); % Numbers that can be increased
idx_fill = randperm(numel(idx_1),remain);
% idx_fill = idx_fill(:,1); % Might be needed
x(idx_1(idx_fill)) = x(idx_1(idx_fill)) + 1;
remain = elem - sum(x);
end
while remain < 0
idx_2 = find(x > 0); % Numbers that can be reduced
idx_red = randperm(numel(idx_2),abs(remain));
% idx_red = idx_red(:,1); % Might be needed
x(idx_2(idx_red)) = x(idx_2(idx_red)) - 1;
remain = elem - sum(x);
end
sum(x)
max(x)
min(x)
ans = 1500
ans = 60
ans = 34
This is an intuitive approach and works nicely for 2D arrays, without "randperm":
N = 36000; % for three hundred years
days = 30; % days
elem = 1500; % elements in ten years
min_x = 0; % daily minimum
max_x = 60; % daily maximum
tic
x = zeros(days, N);
for hh = 1:elem
% Add new candidates
inds = randi(days, N, 1);
inds = ((1:N).' - 1) * days + inds;
x(inds) = x(inds) + 1;
% Check
inds_chck = x > max_x;
any_inds_chck = any(inds_chck);
find_any_inds_chck = find(any_inds_chck);
ctrl = numel(find_any_inds_chck);
while ctrl>0
% First remove baddies
inds = inds(find_any_inds_chck);
x(inds) = x(inds) - 1;
% Then reassign to new candidates
inds = randi(days, ctrl, 1);
inds = (find_any_inds_chck.' - 1) * days + inds;
x(inds) = x(inds) + 1;
% Check again
inds_chck = x(:, find_any_inds_chck) > max_x;
any_inds_chck = any(inds_chck);
find_any_inds_chck = find(any_inds_chck);
ctrl = numel(find_any_inds_chck);
end
end
toc
But the price is a weird probability function:
hist(x(:), max_x - min_x + 1)
Note that the constraint has an obvious effect on the degrees of freedom as well.
Also note that they have tried to answer a similar question in Generate a random number with max, min and mean (average) in Matlab .