How to create a matrix using a for loop MATLAB - matlab

I have three vectors of the same size, pressure, year and month. Basically I would like to create a matrix of pressure values that correspond with the months and years that they were measured using a for loop. It should be 12x100 in order to appear as 12 months going down and 100 years going left to right.
I am just unsure of how to actually create the matrix, besides creating the initial structure. So far I can only find pressure for a single month (below I did January) for all years.
A = zeros([12, 100]);
for some_years = 1900:2000
press = pressure(year == some_years & month == 1)
end
And I can only print the pressures for January for all years, but I would like to store all pressures for all months of the years in a matrix. If anyone can help it would be greatly appreciated. Thank You.

Starting with variables pressure, year, and month. I would do something like:
A fairly robust solution using for loops:
T = length(pressure); % get number of time periods. I will assume vectors same length
if(length(pressure) ~= T || length(month) ~= T)
error('length mismatch');
end
min_year = min(year); % this year will correspond to index 1
max_year = max(year);
A = NaN(max_year - min_year + 1, 12); % I like to initialize to NaN (not a number)
% this way missing values are NaN
for i=1:T
year_index = year(i) - min_year + 1;
month_index = month(i); % Im assuming months run from 1 to 12
A(year_index, month_index) = pressure(i);
end
If you're data is SUPER nicely formatted....
If your data has NO missing, duplicate, or out of order year month pairs (i.e. data is formatted like):
year month pressure
1900 1 ...
1900 2 ...
... ... ...
1900 12 ...
1901 1 ...
... ... ...
Then you could do the ONE liner:
A = reshape(pressure, 12, max(year) - min(year) + 1)';

Related

Split dataset to specific number of sample by for loop

I have a 35136-by-1 matrix containing power data of 366 days with every day having 96 measurements). I want to take a sample from 252 days: power data of "day 1 to day 7" is the first sample, power data of "day 2 to day 8" is the second sample, etc.), and reshape my matrix to size [96 7 1 252].
I wrote following code, but I get 36 sample instead of 252
m=7;
for j=1
sample([j:96*m],:)=solarpower_n([j:96*m],:);
y([(96*m)+1:96*(m+1)],:)=solarpower_n([(96*m)+1:96*(m+1)],:);
m=m+1;
for j=2:246
sample([(96*(j-1))+1:96*m],:)=solarpower_n([(96*(j-1))+1:96*m],:);
y([(96*m)+1:96*(m+1)],:)=solarpower_n([(96*m)+1:96*(m+1)],:);
m=m+1;
end
end
I want to take sample from each 7 days. Assume D to be the number of days, and M as number of power measurements on each day. For 252 days, M=[1,2,3,...,96] and D=[1,2,...,252] . Thus the power of first day, P1, has a dimension of 96*1. I want to take sample1={P1,...,P7}, sample2={P2,...,P8} , .....,sample252={P246,.....,P252}. and have a [96 7 1 252] 4-D array.
How can I accomplish this?
Taking samples that way is rather inefficient, since you're copying each data point 7 times. You could simply use indexing:
A = rand(96*366, 1); % Sample data
B = reshape(A,[96 366]); % Reshape all your days in one go
B(:, 1:7) % first 7 days
B(:, 163:170) % Days 163 to 170, etc.
If you do want to copy your data seven times to your 4D array you can use a simple for loop:
A = rand(96*366, 1); % Sample data
% Note you need days 253:256, since P252 contains those days
B = reshape(A(1:96*(252+6)),[96 (252+6)]); % Reshape your first 252 days
C = zeros(size(B,1), 7, 1, size(B,2)-6); % Initialise output
for ii = 1:size(B,2)-6
C(:, :, :, ii) = B(:, ii:ii+6); % Save each 7 day sample
end
Getting rid of the for loop is difficult, given you want a sliding window. There are probably specialised functions for that somewhere, but given your data size a loop should be sufficiently performant.
For a short introduction on reshape() you can read this answer of mine.

How can I loop through dates and store weight values in a matrix? [MATLAB]

Hi so I am new to MATLAB. I am trying to find the means of weight values for each month over five years and put these values into a matrix that will be 5x12 in size.
I am attempting to accomplish this with a loop but I'm having a little trouble, if anyone can push me towards the right direction that would be awesome, thanks. What I have so far is this:
weight_data = (10 weights per month for 10 years, 1200 weights total)
year = (years 2000-2010) %year 1-10 corresponds with the 1200 weights)
month = (months 1-12) %weights for all months (120 months, correspond with 1200 weights)
weight_vec = zeros([12, 5]);
for n = year(1:5)
weights = weight_data(n);
mean_weights = mean(weights);
end
This only gives me one number though, I assume the mean from the 5 years I'm trying to loop through. I also know I need to incorporate the months somehow but I'm just confused on how to do this.
Being your weight_data matrix (10 weights x 12 months x 10 years), the weight of the i-th year are located in weight_data(:,:,i).
w=weight_data(:,:,i)
w is a (10 x 12) which contains the 10 weights values of the 12 months.
You can use mean to compute the mean value of the weights of each month:
w=mean(weight_data(:,:,i))
Therefore you can setup a loop over the years:
for i=1:1:5
mean_weights(:,i)=mean(weight_data(:,:,i))'
end
(the ' in mean(weight_data(:,:,i))' is required to transpose the output of mean from a row-array to a column-array so that it fits in your output matrix which is (12 x 5)
Hope this helps,
Qapla'

How to loop through a vector that corresponds to another vector MATLAB

I have a column of years from 1981 to 2000 that corresponds to another column of prices for a good. I am trying to make a loop that iterates through only the years from 1990 to 2000 and prints the prices in order that correlates with their year. I have this code so far but I'm not sure why it won't run, any help would be awesome.
for x=1:year == 1990:2000
v = find(isfinite(price));
v
end
If your input data is something like this where the first column is year and the second column is price
data = [1990, 2.50;
1991, 3.00;
...
2000, 4.00];
You can loop through the years in your for loop (Note the syntax and how this compares to the one in your post) and then find the second column where the price corresponds to that year using logical indexing.
for year = 1990:2000
% Grabs column 2 where column 1 is equal to the year
price = data(data(:,1) == year, 2);
end
Even if your data lives in two different data structures you can do something similar (as long as they are the same size).
years = [1990, 1991, 1992, ... 2000];
prices = [2.50, 3.00, 3.50, ... 4.00];
for year = 1990:2000
price = prices(years == year);
end
Edit
If you are for-loop averse, you can definitly do the same thing without a for loop. The most robust solution is to use arrayfun.
annualPrices = arrayfun(#(x)prices(years == x), years, 'uniform', 0);
This will return a cell array where each element is all prices for a given year.
If you're guaranteed to only have one price per year, however, you can omit the uniform input and you'll get an array of prices.
annualPrices = arrayfun(#(x)prices(years == x), years);
One of the benefits is that neither of these approaches requires extra operations (such as sorting) on your data.
Example 1:
Let's make a matrix holding your data:
M = ones(100,2); % 1st column for the year and the second column for the prices
M(:,1) = (1951:2050).';
M(:,2) = rand(100,1);
A one liner to your question can be as follows:
M((M(:,1)<= 2000 & M(:,1) >= 1990),2)
Example 2:
If you have prices and years in two vectors, first make sure your years are sorted:
[sortedYears,Idx] = sort(years); % sort the years vector
sortedPrices = prices(Idx); % use the index to sort the prices in the same order
Now use the following one liner:
sortedPrices((sortedYears<= 2000 & sortedYears >= 1990));

Daily values to Monthly Means for Multiple Years Matlab

I have observed daily data that I need to compare to generated Monthly data so I need to get a mean of each month over the thirty year period.
My observed data set is currently in 365x31 with rows being each day (no leap years!) and the extra column being the month number (1-12).
the problem I am having is that I can only seem to get a script to get the mean of all years. ie. I cannot figure how to get the script to do it for each column separately. Example of the data is below:
1 12 14
1 -15 10
2 13 3
2 2 37
...all the way to 12 for 365 rows
SO: to recap, I need to get the mean of [12; -15; 13; 2] then [14; 10; 3; 37] and so on.
I have been trying to use the unique() function to loop through which works for getting the number rows to average but incorrect means. Now I need it to do each month(28-31 rows) and column individually. Result should be a 12x30 matrix. I feel like I am missing something SIMPLE. Code:
u = unique(m); %get unique values of m (months) ie) 1-12
for i=1:length(u)
month(i) = mean(obatm(u(i), (2:31)); % the average for each month of each year
end
Appreciate any ideas! Thanks!
You can simply filter the rows for each month and then apply mean, like so:
month = zeros(12, size(obatm, 2));
for k = 1:12
month(k, :) = mean(obatm(obatm(:, 1) == k, :));
end
EDIT:
If you want something fancy, you can also do this:
cols = size(obatm, 2) - 1;
subs = bsxfun(#plus, obatm(:, 1), (0:12:12 * (cols - 1)));
vals = obatm(:, 2:end);
month = reshape(accumarray(subs(:), vals(:), [12 * cols, 1], #mean), 12, cols)
Look, Ma, no loops!

matlab updating time vector

I have 19 cells (19x1) with temperature data for an entire year where the first 18 cells represent 20 days (each) and the last cell represents 5 days, hence (18*20)+5 = 365days.
In each cell there should be 7200 measurements (apart from cell 19) where each measurement is taken every 4 minutes thus 360 measurements per day (360*20 = 7200).
The time vector for the measurements is only expressed as day number i.e. 1,2,3...and so on (thus no decimal day),
which is therefore displayed as 360 x 1's... and so on.
As the sensor failed during some days, some of the cells contain less than 7200 measurements, where one in
particular only contains 858 rows, which looks similar to the following example:
a=rand(858,3);
a(1:281,1)=1;
a(281:327,1)=2;
a(327:328,1)=5;
a(329:330,1)=9;
a(331:498,1)=19;
a(499:858,1)=20;
Where column 1 = day, column 2 and 3 are the data.
By knowing that each day number should be repeated 360 times is there a method for including an additional
amount of every value from 1:20 in order to make up the 360. For example, the first column requires
79 x 1's, 46 x 2's, 360 x 3's... and so on; where the final array should therefore have 7200 values in
order from 1 to 20.
If this is possible, in the rows where these values have been added, the second and third column should
changed to nan.
I realise that this is an unusual question, and that it is difficult to understand what is asked, but I hope I have been clear in expressing what i'm attempting to
acheive. Any advice would be much appreciated.
Here's one way to do it for a given element of the cell matrix:
full=zeros(7200,3)+NaN;
for i = 1:20 % for each day
starti = (i-1)*360; % find corresponding 360 indices into full array
full( starti + (1:360), 1 ) = i; % assign the day
idx = find(a(:,1)==i); % find any matching data in a for that day
full( starti + (1:length(idx)), 2:3 ) = a(idx,2:3); % copy matching data over
end
You could probably use arrayfun to make this slicker, and maybe (??) faster.
You could make this into a function and use cellfun to apply it to your cell.
PS - if you ask your question at the Matlab help forums you'll most definitely get a slicker & more efficient answer than this. Probably involving bsxfun or arrayfun or accumarray or something like that.
Update - to do this for each element in the cell array the only change is that instead of searching for i as the day number you calculate it based on how far allong the cell array you are. You'd do something like (untested):
for k = 1:length(cellarray)
for i = 1:length(cellarray{k})
starti = (i-1)*360; % ... as before
day = (k-1)*20 + i; % first cell is days 1-20, second is 21-40,...
full( starti + (1:360),1 ) = day; % <-- replace i with day
idx = find(a(:,1)==day); % <-- replace i with day
full( starti + (1:length(idx)), 2:3 ) = a(idx,2:3); % same as before
end
end
I am not sure I understood correctly what you want to do but this below works out how many measurements you are missing for each day and add at the bottom of your 'a' matrix additional lines so you do get the full 7200x3 matrix.
nbMissing = 7200-size(a,1);
a1 = nan(nbmissing,3)
l=0
for i = 1:20
nbMissing_i = 360-sum(a(:,1)=i);
a1(l+1:l+nbMissing_i,1)=i;
l = l+nb_Missing_i;
end
a_filled = [a;a1];