Pass from multidimensional array to spreadsheet - excel

I have a multidimensional array which of the form:
where each row represents a sheet and each column represents a type of variable.
What I want to do is export the data into a spreadsheet where each row gets stored in a sheet with its columns. (Maybe it could be easier separate the sim multidimensional array into five matrices and then export those together to a spreadsheet) but I don't know if it's the most efficient way.
Here is a image of the spreadsheet:
Below is my code, which basically reads the sheets from a Excel and make a simulation of 1,000 cases for each type of data:
sim={};
for k = 1 : 5
sheet = xlsread('CB.xlsx', k);
[m, n] = size(sheet)
for i = 1 : n
[f,x] = ecdf(sheet(:,[i]));
[f, dup] = unique(f);
x = x(dup);
randomValues = rand(1, 1000);
sim{k,i} = round(interp1(f,x, randomValues));
end
end
trying to use Mikhail_Sam'answer I got the follow problems:
`sheet = 1
for i = 1:5
for j = 1:5
xlswrite('filename.xls',sim(:,i,j),sheet,strcat(char(64+j),int2str(1)))
end
sheet = sheet+1;
end`
but it says "Index exceeds matrix dimensions", then I tried this code
sheet = 1
for i = 1:5
for j = 1:size(sheet)
xlswrite('filename2.xls',sim{i,j},sheet,'A1:E1000');
end
sheet = sheet+1;
end
This code write the file ith the 5 sheets but it is filled with the first 5 numbers of each row of the multidimensional array. Then I tried to apply num2cell and run your code but it gives "index exceeds matrix dimension" again

I don't know about 'the most efficient way', but I did it this way:
for example I create 3x3x3 matrix and try to write it to excel:
sheet = 1
for i = 1:3
for j = 1:3
xlswrite(filename,x(:,i,j),sheet,strcat(char(64+j),int2str(1)));
end
sheet = sheet+1;
end
And I got what you want - 3 sheets, and data in rows.
replace 3 at your dimensions. But I have one weak place - I don't remember numeric mechanism in multidimensional arrays - is i is a row in your example, or j... Anyway it's work just take a look at data and replace i - j - : if necessary.
Hope, it helps :)

Finally I figure out how pass from multidimensional array to each spreadsheet. I decided to arrange the data in the same multidimensional array to then pass the data to a spreadshe, using A{k}=transpose(vertcat(simulado{k,:})) and then apply a for loop to add the data to each sheet separately.
sheet = 1
for i = 1:5
xlswrite('filename.xls',A{1,i},sheet);
sheet = sheet+1;
end`

Related

Equivalent of excel VBA array and loop in Openpyxl

I have been working with excel VBA. I have created a script for comparing the current week's data with the previous week's data and take some actions based on that comparison. This is the code used by me which runs really very efficiently.
arrc = currWs.Range("A1").CurrentRegion 'outer loop array from currWs
arrp = prevWs.Range("A1").CurrentRegion 'inner loop array from prveWs
For y = 1 To UBound(arrc, 1)
For z = 1 To UBound(arrp, 1)
If arrc(y, 5) = arrp(z, 5) Then
currWs.Range("I" & y).Value = "matched"
Exit For
End If
Next z
Next y
I want to replicate the same in python / openpyxl.
(1) Is there a way we can assign a range of values to a python list as given in the vba program? can it be done in a single statement without a loop?
(2) I would also need in python the equivalent of the outer/inner loops given above
As I have to deal with two sets of 300000 rows, the code needs to be efficient.

2D vector lookup [x;y]

I've got a matrix, with two coordinates [i;j]
I'm trying to automatize a lookup:
As an example, this would have the coordinates of [1;2]
Here's a table of all the coordinates:
So here, obviously [1;2] would equate to 143,33
To simplify the issue:
I'll try to go step by step over what I'm trying to do to make the question bit less confusing.
Think of what I'm trying to do as a function, lookup(i, j) => value
Now, refer to the second picture (table)
I find all rows containing index [i] (inside column C) and then
only for those rows find row containing index [j] (inside column D ∩ for rows from previous step)
Return [i;j] value
So if u invoked lookup(2, 4)
Find all rows matching i = 2
Row 5: i = 2 ; j = 3
Row 6: i = 2 ; j = 4
Row 7: i = 2 ; j = 5
Lookup column j for j=4 from found rows
Found row 6: i = 2 ; j = 4.
Return value (offset for yij column = 143,33)
Now this isn't an issue algorhitmically speaking, but I have no idea how to go about doing this with excel formulas.
PS: I know this is reltively simple vba issue but I would prefer formulas
PSS: I removed what I tried to make the question more readable.
You can use SUMPRODUCT, which return 0 for not found values:
=SUMPRODUCT(($C$4:$C$18=$I4)*($D$4:$D$18=J$3)*$E$4:$E$18)
or AGGREGATE, which returns an error that can be hidden by the IFERROR function:
=IFERROR(AGGREGATE(15,6,(1/(($C$4:$C$18=$I12)*($D$4:$D$18=J$3)))*$E$4:$E$18,1),"")
You can use SUMIFS here assuming you will not have exact duplicate combinations of [i, j]. If you did have a duplicate combination, the amounts will be summed and placed in the corresponding cell
In cell B2 place this equation: =SUMIFS($Q$2:$Q$16,$P$2:$P$16,B$1,$O$2:$O$16,$A2) and drag across and over as needed
IF you want to convert the 0's to blanks you can nest the above formula inside a text formatter like so:
=TEXT([formula], "0;-0;;#")

Transposing Data in 1 column by custom delimiters

I've converted a PDF to Excel; All the data is in one column like so:
Item1
Header1
String1
String2
Header2
String1
String2
Item 2
Header1
String1
String2
Header2
String1
String2
The headers are consistent throughout the items. Is there an easy way to transpose this data by custom delimiters (Header1, Header2)?
My goal is to transpose this data as such:
| Header1 | Header2 |
Item1 | String1&String2 | String1&String2 |
Item2 | String1&String2 | String1&String2 |
I'm assuming the most straight-forward way would be writing a custom sorting macro that can sort by the Headers as delimiters
Can anyone give me a jump start?
Manually place the headers in Sheet2, cells B1 and C1 then go back to Sheet1 and run this:
Sub cropier()
Dim N As Long, i As Long, j As Long, K As Long
Dim s1 As Worksheet, s2 As Worksheet
Set s1 = Sheets("Sheet1")
Set s2 = Sheets("Sheet2")
N = Cells(Rows.Count, "A").End(xlUp).Row
K = 2
s = ""
For i = 1 To N
v = s1.Cells(i, "A").Value
j = i Mod 7
Cells(i, "B") = j
Select Case j
Case 1
s2.Cells(K, 1) = v
Case 3
t = v
Case 4
t = t & v
s2.Cells(K, 2) = t
s2.Cells(K, 3) = t
t = ""
K = K + 1
End Select
Next i
End Sub
An alternative approach not using VBA, which is more general than the 2 rows, 2 columns and 2 concatenated strings output shown in your example and which selects the column headings as well as the row headings from the input data...
I shall assume that your data has a structure as follows:
the "body" of the required output table has I rows and J columns
each "cell" of the output table is formed from a concatention of K "data strings"
Your input data list will comprise I item labels, IJ header labels (since there are J header labels per item) and IJK data strings, so I + IJ + IJK =
I(1+J(1+K)) values in total. For convenience number the rows of the input data list sequentially, starting at 1.
The approach is based on picking out the positions within the input data list of the i'th item label, j'th header label and the data strings which comprise the (i,j)th cell. Please note i and j are distinct from I and J.
I will deal with the header labels first as that is possibly the easiest to understand.
Suppose the first header label within an item is at position p in
the input data list. The next header label will occur at 1+K
positions further down the list ie at position p+1+K. If J>2 (ie
more than two header labels in the input data) then the third header
label will occur at p+2(1+K). In general, the header labels will
occur at
p+n(1+K) for n=0,1,...,J-1
I will return to the value of p shortly.
Consider now the item labels. Just as the header labels within an
item occurred every 1+K positions, the item labels occur every
1+J+JK = 1+J(1+K)) positions. Since the first position in the data
list is an item label, the positions of the item labels can be
written generally as
1 + n(1+J(1+K)) n=0,1,...,I-1
Returning to the value of p in 1., the first header label within an
item occurs at the position following an item label. Item labels are
listed in 2. which it is convenient to rewrite as 1 +
(i-1)(1+J(1+K)) i=1,2,...,I. Adding 1 to this expression and
substituting it for p in 1. yields an expression for the positions of
the IJ header labels in the input list as 2+(i-1)(1+J(1+K))+n(1+K) i=1,2,...,I n=0,...,J-1. This expression can be slightly rewritten as 2+(i-1)(1+J(1+K)) + (j-1)(1+K) i=1,2,...,I; j=1,2...,J.
The final expression in 3. provides much that is needed for the
positions of the data strings. These occur in the K positions after
the header labels. So the first data string is obtained by adding 1
to this expression, the second by adding 2,...,and the last by
adding K.
This now gives all the positional information to construct the output table.
The row labels (items) are given by the rewritten version of the expression in 2. ie 1 + (i-1)(1+J(1+K)) i=1,2,...,I. These label positions are a function of i.
The column labels (headers) are given by the final expression in 3. and since these labels are repeated for each item, any value of i can be chosen. Taking i as 1 simplifies the formula to 2+(j-1)(1+K) j=1,2...,J. These label positions are a function of j.
The (i,j)th cell of the output table is a concatentation of the strings starting at position 3+(i-1)(1+J(1+K)) + (j-1)(1+K) and ending at position (2+K)+(i-1)(1+J(1+K)) + (j-1)(1+K) (where i is between 1 and I and j is between 1 and J). The positions of the data strings are a function of i and j.
This positional information now allows construction of an output table with I rows and J columns in its body and including row and column header labels. The table can be constructed in the usual way from an I*1 column containing 1,...,I and a 1*J row containing 1,...,J. (Typically this column and this row are positioned to the left of and above the output, respectively, but could be placed anywhere in the workbook.)
UPDATE Worked example based on 3 items, 4 headers and 5 strings per output cell is here

How to recreate Excel's "Index(,,Match())" function in SPSS?

I am trying to recreate Excel's "Index(,,Match())" function in SPSS. My data is organized as follows:
The "Position" variables indicate what column (T:V) the value in the "Value" variables should go.
In the 1st row, the positions are in order 1-3, so the values in columns T:V are in the same order as the "Value" variables.
In the second row the positions are 2,3,1; so the value in "Value1" should go in column U (the second column in that last block of variables), the value in "Value2" should go in the column V, and the value in "Value 3 should go in column T. And so on.
After looking into doing this in SPSS, SPSS' Index and Match functions will not help.
Do any Excel/SPSS users know how to accomplish this in SPSS with syntax?
There are probably several ways to approach the problem, depending on how many columns you're dealing with and whether they're all numeric or if there are strings (there's probably a matrix algebra answer, I just can't think of it).
If you only have 3 sets of 3 columns, the simplest approach would be to write 9 (3*3) if-statements (you don't have column names for cols T/U/V, so I'm just referencing their Excel column):
if (Position1 = 1) T = Value1.
if (Position1 = 2) T = Value2.
if (Position1 = 3) T = Value3.
if (Position2 = 1) U = Value1.
if (Position2 = 2) U = Value2.
...
This should work. If you have many more columns, you can also use vector loops to define the sets of variables.
Here's a scalable approach:
vector match(3).
do repeat p = position1 to position3 / v= value1 to value3 / y = #y1 to #y3.
compute y = v*p.
end repeat.
loop #i = 1 to 3.
compute match(#i) = any(#i, #y1 to #y3).
end loop.
exe.

Get maximum value of columns in Excel with macro

First of all I have no idea of writing macros in excel, but now I have to write a code for a friend. So here we go.
In my excel sheet I have a table which holds some producers as columns and 12 months of the year as rows. In their intersecting cell it's written the amount of products produced by the producer during that month. Now I need to find maximum and minimum values of produced goods within each month and output the producers of that goods.
I found a code for a similar problem, but I don't understand it clearly and it has errors.
Here is the code:
Sub my()
Dim Rng As Range, Dn As Range, Mx As Double, Col As String
Set Rng = Range(Range("A1"), Range("A6").End(xlUp))
ReDim ray(1 To Rng.Count)
For Each Dn In Rng
Mx = Application.Max(Dn)
Select Case Mx
Case Is = Dn.Offset(, 0): Col = "A"
Case Is = Dn.Offset(, 1): Col = "B"
Case Is = Dn.Offset(, 2): Col = "C"
Case Is = Dn.Offset(, 3): Col = "D"
End Select
ray(Dn.Row - 1) = Col
Next Dn
Sheets("Sheet2").Range("A2").Resize(Rng.Count) = Application.Transpose(ray)
End Sub
I get the following error:
Run-time error'9': Subscript out of range.
So my question is, what does this error mean and what do I need to change in this code to work?
EDIT1:
OK, now the error is gone. But where do I get the results?
EDIT2
I know this line is responsible for inserting the results in specified place, but I cant see them after execution. What's wrong with that?
Error means the array you are trying to access has not been defined to contain the ordinal you're looking for: For example Array 10 has positions 0-9 so if I try and access array(10) it would throw that error or array(-1) it would throw that error.
I can't remember if excel is 0 or 1 based arrays.
Possibly change
ray(Dn.Row - 1) = Col
to
if dn.row-1<> 0 then ' or set it to <0 if zero based.
ray(Dn.Row - 1) = Col
end if
You don't need VBA (a macro) to do this. It can be done using a worksheet formula.
E.g.
If your producers are P1,P2,P3,P4 and your sheet looks like this:-
A B C D E F
+-------------------------------------------
1 | Month P1 P2 P3 P4 Top Producer
2 | Jan 5 4 3 2
3 | Feb 2 3 5 1
4 | Mar 6 4 4 3
...
...
The following formula placed in cells F2,F3,F4,... will pick out the top producer in each month.
=INDEX($B$1:$E$1,MATCH(MAX(B2:E2),B2:E2,0))
Generally it's better to try and use built in Excel functionality where possible. Resort to VBA only if you really need to. Even if you were to use the top producer/month data for some other operation which is only possible in VBA, at least the top producer/month data derivation is done for you by the worksheet, which will simplify the VBA required for the whole process.
Transposing a range can also be done using a worksheet formula by using the TRANSPOSE() function.
BTW - I'm not sure what you want to do if two producers have the same output value. In the VBA example in your question, the logic seems to be:- if two producers are joint top in a month, pick the first one encountered. The formula I've given above should replicate this logic.
I have used these functions quite extensively and they are very reliable and fast:
Public Function CountRows(ByRef r As Range) As Integer
CountRows = r.Worksheet.Range(r, r.End(xlDown)).Rows.Count
End Function
Public Function CountColumns(ByRef r As Range) As Integer
CountColumns = r.Worksheet.Range(r.End(xlToRight), r).Columns.Count
End Function
Give it a reference (ex. "A2") and it will return the filled cells down, or the the right until and empty cell is found.
To select multiple sells I usually do something like
Set r = Range("A2")
N = CountRows(r)
Set r = r.Resize(N,1)

Resources