Conditional list values replacement in Mathematica
Please consider :
dalist = Transpose@{{"Noise1",1,1,1,1,1},{"Blah", 1, 2, 3,开发者_运维知识库 4, 5},
{"Noise2",2,2,2,2,2}, {"COGCondition", 1, 2, 1, 2, 1}}
COGCondition1 = 10
COGCondition2 = 20
I would like to replace the values in column "Blah" given the value taken in column "COGCondition" such that:
If, for a given row, the value in column "COGCondition" = 1 the value in column "Blah" should be equal to COGCondition1 (And 2 -> COGCondition2)
Desired output:
I need this for a large data set and my attempts using Table
and Switch
have failed. I can easily generate new columns but can't figure out how to replace values using Switch
.
This is fairly straightforward with a replacement rule:
dalist /.
{x_?NumericQ, y_?NumericQ} :>
{Which[y==1, COGCondition1, y==2, COGCondition2], y}
gives
{{"Blah", "COGCondition"}, {10, 1}, {20, 2}, {10, 1}, {20, 2}, {10, 1}}.
Alternatively, you could use MapThread
MapThread[
If[ !NumericQ[#2], #1,
Which[#2==1, COGCondition1, #2==2, COGCondition2] ]&,
Transpose@dalist]
which returns
{"Blah", 10, 20, 10, 20, 10}.
Edit: In your updated version of dalist
, you have four columns: noise, data, noise, and condition. The update to the pattern version is simply
dalist /.
{a_, x_, b_, y_} :>
{a, Which[y==1, COGCondition1, y==2, COGCondition2], b, y}
Unfortunately, this is somewhat fragile because it requires a bit of extra work if you change the number of conditions. The method suggested by Leonid, was to create a function
Clear[COGCondition]
COGCondition[1] = 10
COGCondition[2] = 20
then this simplifies the update code
dalist /.
{a_, x_, b_, y_Integer} :> {a, COGCondition[y], b, y}
Alternatively, you could create a list of rules
conditions = { 1 -> 10, 2 -> 20 }
then the code for changing dalist
becomes
dalist /.
{a_, x_, b_, y_Integer} :> {a, y /. conditions, b, y}
If you find that you have more than 1 column between x
and y
, then your pattern is simply {a_, x_, b___, y_Integer}
. Or, if the number of columns prior to x
is larger than one, use {a___, x_, b_, y_Integer}
. However, they don't work together because Mathematica needs to know where x
and y
are relative to some point in the list, or it won't operate as you expect, if at all.
But, if you know the number of columns, you can use PatternSequence
. For example, if you have 3 columns of noise, your data, 5 columns of noise, and then you condition, your replacement rule would be
dalist /.
{a:PatternSequence@@Array[_&,3], x_,
b:PatternSequence@@Array[_&,5], y_Integer} :> {a, y /. conditions, b, y}
Now, PatternSequence@@Array[_&,3]
could be written PatternSequence[_, _, _]
, but by using Array
it gives more flexibility.
Edit: One difficulty with either the indexed variable form, COGCondition[n]
, or the rule form is if the condition column contains values other than 1 or 2. The simplest solution is to set up a default value, e.g.
COGCondition[_] := default (*where default may be defined elsewhere *)
or add to conditions
_ :> default
One possibility is to emit a Message
whenever this default is encountered which would provide feed back as its running.
Another possibility is to have the data column remain untouched if the default is encountered. To accomplish this, we can use the following
COGCondition[1,_] := 10
(*define the rest of the known values as above*)
COGCondition[_,d_]:= default (*encountered only if the 1st var is unknown*)
which would be used like
dalist /.
{a_, x_, b_, y_Integer} :> {a, COGCondition[y, x], b, y}.
To make this work with the rule implementation, we make conditions
a function which accepts the current data value
conditions[dat_] := { 1 -> 10, 2 -> 20, _ :> dat }
which changes the code for updating dalist
to
dalist /.
{a_, x_, b_, y_Integer} :> {a, y /. conditions[x], b, y}.
Note, either of the last two methods can be combined with emitting a Message
from above.
I would use:
dalist[[2 ;;, 2]] =
dalist[[2 ;;, 4]] /. {1 -> COGCondition1, 2 -> COGCondition2};
dalist //TableForm
If modification of dalist
is undesired, you can copy it first, e.g. dalist2 = dalist
and then modify the copy.
Especially if you have many values for the condition column, I suggest you follow the earlier recommendation to use an indexed variable (COGCondition[1]
). This would look like:
dalist[[2 ;;, 2]] = COGCondition /@ dalist[[2 ;;, 4]];
精彩评论