Conditional list values replacement in Mathematica

冷暖自知 提交于 2019-12-24 03:14:08

问题


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.


回答1:


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]];



回答2:


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.



来源:https://stackoverflow.com/questions/7079244/conditional-list-values-replacement-in-mathematica

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!