Weight factors by eigenvalues from PROC FACTOR in SAS? - statistics

I am trying to weight the factors from PROC FACTOR by their eigenvalues, but am having some difficulty. I have a solution, but it seems to me that there should be a more direct way to do this.
** Get factors and eigenvalues;
ods output Eigenvalues=MyEigenVals
proc factor data=MyData method=principal out=MyData;
var X1 X2 X3 X4 X5 X6;
run;
ods output close;
** Transpose the eigenvalues;
proc transpose data=MyEigenVals out=MyEigenVals(drop=_NAME_) prefix=eigenval;
id Number;
var Eigenvalue;
run;
** Merge the data and fill down the eigenvalues;
data MyData;
merge MyData MyEigenVals;
retain E1 E2 E3 E4 E5 E6;
if _n_=1 then do;
E1 = eigenval1;
E2 = eigenval2;
E3 = eigenval3;
E4 = eigenval4;
E5 = eigenval5;
E6 = eigenval6;
end;
** weight each factor by its eigenvalue;
factor1 = factor1 * E1;
factor2 = factor2 * E2;
factor3 = factor3 * E3;
factor4 = factor4 * E4;
factor5 = factor5 * E5;
factor6 = factor6 * E6;
run;
As you can see this does not seem to be a very direct way of accomplishing my task. Can anyone here help me fix this up nicely? Is it even possible?

You definitely could combine it more efficiently; at minimum, you can simplify the last datastep.
data mydata;
if _n_=1 then set MyEigenVals;
set mydata;
array factor[6];
array Eigenval[6];
do _i = 1 to dim(factor);
factor[_i] = factor[_i]*eigenval[_i];
end;
run;
SET automatically retains variables.
Secondly, you may be able to skip the multiplication depending on how you're using the results. You might be able to use a weight statement to use the eigenvalues as weights - depending on what procedures you're using to later analyze the data. I don't know if that buys you much, but it could save you from modifying the original value which might be preferable.

Related

Open Scene Graph - Usage of DrawElementsUInt: Drawing a cloth without duplicating vertices

I am currently working on simulating a cloth like material and then displaying the results via Open Scene Graph.
I've gotten the setup to display something cloth like, by just dumping all the vertices into 1 Vec3Array and then displaying them with a standard Point based DrawArrays. However I am looking into adding the faces between the vertices so that a further part of my application can visually see the cloth.
This is currently what I am attempting as for the PrimitiveSet
// create and add a DrawArray Primitive (see include/osg/Primitive). The first
// parameter passed to the DrawArrays constructor is the Primitive::Mode which
// in this case is POINTS (which has the same value GL_POINTS), the second
// parameter is the index position into the vertex array of the first point
// to draw, and the third parameter is the number of points to draw.
unsigned int k = CLOTH_SIZE_X;
unsigned int n = CLOTH_SIZE_Y;
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_QUADS, (k) * (n));
for (uint y_i = 0; y_i < n - 1; y_i++) {
for (uint x_i = 0; x_i < k - 1; x_i++) {
(*indices)[y_i * k + x_i] = y_i * k + x_i;
(*indices)[y_i * (k + 1) + x_i] = y_i * (k + 1) + x_i;
(*indices)[y_i * (k + 1) + x_i + 1] = y_i * (k + 1) + x_i + 1;
(*indices)[y_i * k + x_i] = y_i * k + x_i + 1;
}
}
geom->addPrimitiveSet(indices.get());
This does however cause memory corruption when running, and I am not fluent enough in Assembly code to decipher what it is trying to do wrong when CLion gives me the disassembled code.
My thought was that I would iterate over each of the faces of my cloth and then select the 4 indices of the vertices that belong to it. The vertices are inputted from top left to bottom right in order. So:
0 1 2 3 ... k-1
k k+1 k+2 k+3 ... 2k-1
2k 2k+1 2k+2 2k+3 ... 3k-1
...
Has anyone come across this specific use-case before and does he/she perhaps have a solution for my problem? Any help would be greatly appreciated.
You might want to look into using DrawArrays with QUAD_STRIP (or TRIANGLE_STRIP because quads are frowned upon these days). There's an example here:
http://openscenegraph.sourceforge.net/documentation/OpenSceneGraph/examples/osggeometry/osggeometry.cpp
It's slightly less efficient than Elements/indices, but it's also less complicated to manage the relationship between the two related containers (the vertices and the indices).
If you really want to do the Elements/indices route, we'd probably need to see more repro code to see what's going on.

Correct use of cos() and sin() in Python

I'm trying to convert, just for fun, a code listing written in a language called Seed7 into Python. I've got it just about to beta phase, except for one part. This is the extract of the Seed7 listing:
x1 := flt(column) + 0.5;
y1 := flt(row) + 0.5;
angle := (course - 1.0) * 0.785398;
delta_x := cos(angle);
delta_y := -sin(angle);
inquad := TRUE;
blocked := FALSE;
number := 1;
while number <= distance do
y1 := y1 + delta_y;
x1 := x1 + delta_x;
row := trunc(y1);
column := trunc(x1);
if column < 1 or column > 8 or row < 1 or row > 8 then
inquad := FALSE;
number := distance;
else
if sect[row][column] <> 1 then (* Object blocking move *)
blocked := TRUE;
number := distance;
end if;
end if;
incr(number);
end while;
Which all makes sense, except for the fact that I don't understand how the functions cos() and sin() work in Seed7.
The manual says:
sin
const func float: sin (in float: x)
Compute the sine of x, where x is given in radians.
Returns:
the trigonometric sine of an angle.
but I can't make the equivalent in Python.
This problem is purely one caused by me not understanding Python properly (and not really being that great with maths either), so I come here to ask someone who does understand these things.
What code is required to make the above code work in Python? Help!!! :-)
Many thanks,
Joseph.
Edit: I think the problem is the incr() function. Basically, it is possible to warp in this game less than 1. From the help files:
writeln("Warp - One warp moves you the width of a quadrant. A warp of .5 will move you");
writeln("halfway through a quadrant. Moving diagonally across a quadrant to the next");
writeln("will require 1.414 warps. Warp 3 will move you 3 quadrants providing nothing");
writeln("in your present quadrant blocks your exit. Once you leave the quadrant that");
writeln("you were in, you will enter hyperspace; coming out of hyperspace will place you");
writeln("randomly in the new quadrant. Klingons in a given quadrant will fire at you");
writeln("whenever you leave, enter, or move within the quadrant. Entering a course or");
writeln("warp of zero can be used to return to the command mode.")
My code looks like this:
x1 = float(column) + 0.5
y1 = float(row) + 0.5
angle = (course - 1.0) * 0.785398
deltaX = math.cos(angle)
deltaY = -math.sin(angle)
inQuad = True
blocked = False
num = 1
while num <= distance:
y1 += deltaY
x1 += deltaX
row = int(round(y1))
column = int(round(x1))
if column < 0 or column > 7 or row < 0 or row > 7:
inQuad = False
num = distance
else:
if sect[row][column] != 1:
blocked = True
num = distance
num += 1
The thing is I'm using num+=1 at the end there, as opposed to incr, but I don't understand incr. As I have said, I've been a bit long out of the game, and certain things are really catching me out.
Any help in shining a light would be appreciated.
Joseph.
A guess:
If Seed7 expects radians, you may need to convert degrees to radians before applying sin or cos:
import math
math.sin(math.radians(1))

SAS simplify the contents of a variable

In SAS, I've a variable V containing the following value
V=1996199619961996200120012001
I'ld like to create these 2 variables
V1=19962001 (= different modalities)
V2=42 (= the first modality appears 4 times and the second one appears 2 times)
Any idea ?
Thanks for your help.
Luc
For your first question (if I understand the pattern correctly), you could extract the first four characters and the last four characters:
a = substr(variable, 1,4)
b = substrn(variable,max(1,length(variable)-3),4);
You could then concatenate the two.
c = cats(a,b)
For the second, the COUNT function can be used to count occurrences of a string within a string:
http://support.sas.com/documentation/cdl/en/lefunctionsref/63354/HTML/default/viewer.htm#p02vuhb5ijuirbn1p7azkyianjd8.htm
Hope this helps :)
Make it a bit more general;
%let modeLength = 4;
%let maxOccur = 100; ** in the input **;
%let maxModes = 10; ** in the output **;
Where does a certain occurrence start?;
%macro occurStart(occurNo);
&modeLength.*&occurNo.-%eval(&modeLength.-1)
%mend;
Read the input;
data simplified ;
infile datalines truncover;
input v $%eval(&modeLength.*&maxOccur.).;
Declare output and work variables;
format what $&modeLength..
v1 $%eval(&modeLength.*&maxModes.).
v2 $&maxModes..;
array w {&maxModes.}; ** what **;
array c {&maxModes.}; ** count **;
Discover unique modes and count them;
countW = 0;
do vNo = 1 to length(v)/&modeLength.;
what = substr(v, %occurStart(vNo), &modeLength.);
do wNo = 1 to countW;
if what eq w(wNo) then do;
c(wNo) = c(wNo) + 1;
goto foundIt;
end;
end;
countW = countW + 1;
w(countW) = what;
c(countW) = 1;
foundIt:
end;
Report results in v1 and v2;
do wNo = 1 to countW;
substr(v1, %occurStart(wNo), &modeLength.) = w(wNo);
substr(v2, wNo, 1) = put(c(wNo),1.);
put _N_= v1= v2=;
end;
keep v1 v2;
The data I testes with;
datalines;
1996199619961996200120012001
197019801990
20011996199619961996200120012001
;
run;

Proc Reg Make Prediction With New Observations

I am trying to create a prediction interval based on a linear model in SAS. My SAS code is
proc reg data=datain.aswells alpha=0.01;
model arsenic = latitude longitude depth_ft / clb;
run;
I wish to make a 95% prediction interval with latitude=23.75467, longitude=90.66169, and depth_ft=25. This data point does not exist in the data set, but it is in the range of values used to compute the model. Is there an easy way of accomplishing this in SAS? Shouldn't there be a way to compute this prediction interval in SAS easily?
The easiest thing to do is to add it to your input data set with a missing value for ARSENIC. Then use the OUTPUT statement to output the prediction intervals.
Here is an example:
data test;
do i=1 to 100;
x1 = rannor(123);
x2 = rannor(123)*2 + 1;
y = 1*x1 + 2*x2 + 4*rannor(123);
output;
end;
run;
data test;
set test end=last;
output;
if last then do;
y = .;
x1 = 1.5;
x2 = -1;
output;
end;
run;
proc reg data=test alpha=.01;
model y = x1 x2;
output out=test_out(where=(y=.)) p=predicted ucl=UCL_Pred lcl=LCL_Pred;
run;
quit;
The WHERE clause on the output filters the resulting set to just the missing value to be predicted. You can remove it and get all predicted values and prediction intervals.

How can I find the general form equation of a line from two points?

Given the input:
double x1,y1,x2,y2;
How can I find the general form equation (double a,b,c where ax + by + c = 0) ?
Note: I want to be able to do this computationally. So the equivalent for slope-intercept form would be something like:
double dx, dy;
double m, b;
dx = x2 - x1;
dy = y2 - y1;
m = dy/dx;
b = y1;
Obviously, this is very simple, but I haven't been able to find the solution for the general equation form (which is more useful since it can do vertical lines). I already looked in my linear algebra book and two books on computational geometry (both too advanced to explain this).
If you start from the equation y-y1 = (y2-y1)/(x2-x1) * (x-x1) (which is the equation of the line defined by two points), through some manipulation you can get (y1-y2) * x + (x2-x1) * y + (x1-x2)*y1 + (y2-y1)*x1 = 0, and you can recognize that:
a = y1-y2,
b = x2-x1,
c = (x1-x2)*y1 + (y2-y1)*x1.
Get the tangent by subtracting the two points (x2-x1, y2-y1). Normalize it and rotate by 90 degrees to get the normal vector (a,b). Take the dot product with one of the points to get the constant, c.
If you start from the equation of defining line from 2 points
(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1)
you can end up with the next equation
x(y2 - y1) - y(x2 - x1) - x1*y2 + y1*x2 = 0
so the coefficients will be:
a = y2 - y1
b = -(x2 - x1) = x1 - x2
c = y1*x2 - x1*y2
My implementation of the algorithm in C
inline v3 LineEquationFrom2Points(v2 P1, v2 P2) {
v3 Result;
Result.A = P2.y - P1.y;
Result.B = -(P2.x - P1.x);
Result.C = P1.y * P2.x - P1.x * P2.y;
return(Result);
}
Shortcut steps:
"Problem : (4,5) (3,-7)"
Solve:
m=-12/1 then
12x-y= 48
"NOTE:m is a slope"
COPY THE NUMERATOR, AFFIX "X"
Positive fraction Negative sign on between.
(tip: simmilar sign = add + copy the sign)
1.Change the second set into opposite signs,
2.ADD y1 to y2 (means add or subtract them depending of the sign),
3.ADD x1 to x2 (also means add or subtract them depending of the sign),
4.Then Multiply 12 and 1 to any of the problem set.
After that "BOOM" Tada!, you have your answer
#include <stdio.h>
main()
{
int a,b,c;
char x,y;
a=5;
b=10;
c=15;
x=2;
y=3;
printf("the equation of line is %dx+%dy=%d" ,a,b,c);
}

Resources