Subscribe Bookmark RSS Feed

perform calculation evaluation in associative array

swu2

Occasional Contributor

Joined:

Jan 27, 2017

Hello,

 

I am trying to get a function to return a standard deviation calculation stored inside an associative array, my code will only return the expression of the associative array and not the calculation.  would you please tell me what is wrong with my code.

 

 

cvf= Max(replist);// my cvf in the file is 8

cv=Associative Array();

cv[6]=Associative Array({(Std Dev(5,6,7,8,9,10))});

cv[8]=Associative Array ({(Std Dev(5,6,7,8,9,10,11,12))});

cv[12]=Associative Array ({(Std Dev(5,6,7,8,9,10,11,12,13,14,15,16))});

 

CVC = Function({ref},Local ({cv = Associative Array({cvf, Eval(cvf)} )},cv << get values(cvf));cv[ref]););

a=CVC(cvf);

eval(eval expr(a));

Show(a);

 

this is the output that I get:

a = Associative Array({{Std Dev( 5, 6, 7, 8, 9, 10, 11, 12 ), 1}}, 0);

 

this is the output that I want: a= 2.5

 

2 ACCEPTED SOLUTIONS

Accepted Solutions
swu2

Occasional Contributor

Joined:

Jan 27, 2017

Solution

Hi Mark ,

 

I use your example and I am able to get the row number correctly, but the average and standard deviation is not correct. And my table is over 10,000 line, the calculation is bit slow. Would you please tell me where do I did wrong? thanks.

 

Names Default to Here( 1 );

 

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

 

Summarize( age grp = By( :age),sex grp= By (:sex), avg = Mean( :height ), sd = Std Dev( :height ) );

age grp = Associative Array( :age ) << Get Keys;

sex grp = Associative Array( :sex ) << Get Keys;

 

dt << New Column( "CV" );

 

For( g = 1, g <= nitems(age grp), g++,

for (i =1, i<=nitems(sex grp), i++,

rows = dt <<get rows where(:age == age grp[g] & :sex == sex grp[i]);

:CV[rows] = 100 * sd[i] / avg[i];

 

));

ian_jmp

Staff

Joined:

Jun 23, 2011

Solution

You could try to see if this is more effcient (which I might expect):

Names Default To Here( 1 );
// Example table
dt = Open("$SAMPLE_DATA/Big Class.jmp");
// Edit to taste . . .
var = Column(dt, "height");
byVars = {Column(dt, "sex"), Column(dt, "age")};
// Use a summary table with formula column
dt2 = dt << Summary(Group(byVars), Mean(var), Std Dev(var));
Column(dt2, 4) << setName("Mean");
Column(dt2, 5) << setName("StdDev");
dt2 << New Column( "CV", Numeric, "Continuous", Format( "Percent", 12, 3 ), Formula(:StdDev/:Mean));

If you need the CV values in the original table, use 'Tables > Join'.

10 REPLIES
swu2

Occasional Contributor

Joined:

Jan 27, 2017

I figure out my problem, but I have a new problem.

 

my associateive array is a formula, and I need to retrive the key to perform the calculation.

my code will return a, which is the formula on how to calculate standard deviation. but when I put the formula into a new formula, the new formula doesn't perform the calcualtion.

 

a=CVC(cvf)<<get keys(cvf);

 

show(a);// this is the formula with a:

{Std Dev(:INSTRUMENT_SIGNAL[Row() + 8], :INSTRUMENT_SIGNAL[Row() + 1], :INSTRUMENT_SIGNAL[Row() + 2], :INSTRUMENT_SIGNAL[Row() + 3], :INSTRUMENT_SIGNAL[Row() + 4], :INSTRUMENT_SIGNAL[Row() + 5], :INSTRUMENT_SIGNAL[Row() + 6], :INSTRUMENT_SIGNAL[Row() + 7])};

 

but once I put a into the new formula below: a would do the calculation. Please help!

 

col2<<set formula(If( :RUNSAMPLEKIND == "TITERC.NEG",(a/ :Average Signal) * 100),

If( :RUNSAMPLEKIND[Row()] == :RUNSAMPLEKIND[Row() + 1],

If( :REP[Row()] != 2,(Std Dev( :INSTRUMENT_SIGNAL[Row() + 1], :INSTRUMENT_SIGNAL[Row()] ) /:Average Signal) * 100)));

markbailey

Staff

Joined:

Jun 23, 2011

Let's start over.

  • What are you trying to do?
  • What is your data like?
  • How is it organized?
  • What are the results you need?
  • What do you want to do with the results?

It isn't clear to me that you need to use an associative array.

Learn it once, use it forever!
swu2

Occasional Contributor

Joined:

Jan 27, 2017

there are three columns in a data table, and one will indicate replicate number, and the other will have a signal output for the replicate, and the last one will have the dataID. and I need to calculate the standard deviation for all dataID. all of the data will only have two replicate, except one specific type named "Titer" and depending on the where the data is generated, data type "Titer" can have 6, 8 or 12 replicate. hence, i make those three cases as an array and link them to the replicate column.

 

my code and return the formula to standard devaition calculation, however, when I put those in a new columns for CV calcualtion, it doesn't do anything.

 

the other option that I can think is using the Tabulate platform to get the standard devation and put them in an array and assign them back to the new column. Any suggestion?

markbailey

Staff

Joined:

Jun 23, 2011

Try this example:

Names Default to Here( 1 );

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

Summarize( age grp = By( :age ), avg = Mean( :height ), sd = Std Dev( :height ) );
age grp = Associative Array( :age ) << Get Keys;

dt << New Column( "CV" );

For( g = 1, g <= N Items( age grp ), g++,
	rows = dt << Get Rows Where( :age == age grp[g] )
	:CV[rows] = 100 * sd[g] / avg[g];
);
Learn it once, use it forever!
swu2

Occasional Contributor

Joined:

Jan 27, 2017

Thank, it is want I am looking for. thank you.

 

Shu

swu2

Occasional Contributor

Joined:

Jan 27, 2017

Solution

Hi Mark ,

 

I use your example and I am able to get the row number correctly, but the average and standard deviation is not correct. And my table is over 10,000 line, the calculation is bit slow. Would you please tell me where do I did wrong? thanks.

 

Names Default to Here( 1 );

 

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

 

Summarize( age grp = By( :age),sex grp= By (:sex), avg = Mean( :height ), sd = Std Dev( :height ) );

age grp = Associative Array( :age ) << Get Keys;

sex grp = Associative Array( :sex ) << Get Keys;

 

dt << New Column( "CV" );

 

For( g = 1, g <= nitems(age grp), g++,

for (i =1, i<=nitems(sex grp), i++,

rows = dt <<get rows where(:age == age grp[g] & :sex == sex grp[i]);

:CV[rows] = 100 * sd[i] / avg[i];

 

));

ian_jmp

Staff

Joined:

Jun 23, 2011

Solution

You could try to see if this is more effcient (which I might expect):

Names Default To Here( 1 );
// Example table
dt = Open("$SAMPLE_DATA/Big Class.jmp");
// Edit to taste . . .
var = Column(dt, "height");
byVars = {Column(dt, "sex"), Column(dt, "age")};
// Use a summary table with formula column
dt2 = dt << Summary(Group(byVars), Mean(var), Std Dev(var));
Column(dt2, 4) << setName("Mean");
Column(dt2, 5) << setName("StdDev");
dt2 << New Column( "CV", Numeric, "Continuous", Format( "Percent", 12, 3 ), Formula(:StdDev/:Mean));

If you need the CV values in the original table, use 'Tables > Join'.

ian_jmp

Staff

Joined:

Jun 23, 2011

Not sure when it appeared, but FYI, I just noticed that in my version of JMP (13), "CV' is one of the statistics provided by 'Tables > Summary'. So the formula column is not needed.

markbailey

Staff

Joined:

Jun 23, 2011

I apologize for missing the fact that you have two grouping variables. This modified script will show you how it works.

Names Default to Here( 1 );

// Open example of a data table
dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

// Estimate group statistics and group identities
Summarize( age sex grp = By( :age, :sex ), avg = Mean( :height ), sd = Std Dev( :height ) );

// Make a new columns for group result
dt	<< New Column( "Avg" ) << New Column( "SD" ) << New Column( "CV" );

// Iterate over groups
For( g = 1, g <= N Items( age grp ), g++,
	// Convert :age level to match data type of identity
	rows = dt << Get Rows Where( Char( :age ) == age sex grp[1][g] & :sex == age sex grp[2][g] );
	:Avg[rows] = avg[g];
	:SD[rows] =sd[g];
	:CV[rows] = 100 * sd[g] / avg[g];
);

I don't think that an associative array is the most efficient way to identify the groups. The Summarize() function simultaneously estimates the group statistics and identifies the associated group using two parallel lists of group levels. The only downside, in my opinion, is that the grouping levels are always character strings even if the original levels are numeric, such as :age levels in this case. So I had to convert the :age level for the comparison used in getting the target row numbers.

Now you have two approaches, including Ian's solution using Summary command\.

Learn it once, use it forever!