1
$\begingroup$
  1. Write a block of code that generates a 4x4 matrix with randomized real number entries each between 0 & 1, then selects 3 matrix entries at random, and finally replaces these 3 entries with a "nan" string.

  2. Next, create a function to replace each "nan" in the matrix you just generated with the mean of the numbers that appear in that column. Note that you are safe in assuming that each column contains at least one real number. Throughout this problem, use list manipulations, patterns, and rules, but not loops.

Here is what I did for part (1):

 mat = RandomReal[{0, 1}, {4, 4}]

newMat = mat /. {mat[[RandomInteger[{1, 4}]]][[RandomInteger[{1, 
     4}]]] -> "nan", 
mat[[RandomInteger[{1, 4}]]][[RandomInteger[{1, 4}]]] -> "nan", 
mat[[RandomInteger[{1, 4}]]][[RandomInteger[{1, 4}]]] -> "nan"}

But the problem with this is that sometimes, we may choose the same matrix entry twice, resulting in a matrix with only 2 or possibly 1 deleted element! This obviously doesn't work then.

I was thinking of flattening the matrix and then somehow picking out three distinct elements in this list and then replacing them with "nan". How do I randomly pick three things so that hey are distinct and then replace them with "nan"? From there I would just repartition the list.

For part (2), I'm really stuck. I know I'll have to transpose the matrix and then take the mean of each list, but the problem with that is: how do I take the mean of a list with an "nan" string in it? How do I disregard the string in the list? I also don't know how I can do this without flattening the whole matrix out, thus losing the data for each column.

I was thinking about doing using Cases within Cases. Is that a good start?

$\endgroup$
  • 1
    $\begingroup$ RandomSample. DeleteCases. $\endgroup$ – Sjoerd C. de Vries Oct 30 '14 at 6:33
  • $\begingroup$ Something like this? flatMat = Flatten[mat] then flatMat /. {RandomSample[flatMat, 3] -> {"nan", "nan", "nan"}} $\endgroup$ – Sultan of Swing Oct 30 '14 at 6:46
  • $\begingroup$ list = RandomSample[flatMat, 3]; and Partition[ flatMat /. {x_ /; x === list[[1]] -> "nan", x_ /; x === list[[2]] -> "nan", x_ /; x === list[[3]] -> "nan"}, 4] solves part 1. Thanks. Now on to part (2)... $\endgroup$ – Sultan of Swing Oct 30 '14 at 6:55
1
$\begingroup$

You can simply consider Mean as Total of real values divided by the number of real values:

n = {4, 4};
k = 3;
mat = RandomReal[1, n];
mat // MatrixForm

enter image description here

newMat = ReplacePart[mat, RandomSample[Tuples@Range@n, k] -> "nan"];
newMat // MatrixForm

enter image description here

Total[newMat /. "nan" -> 0]/Total@Replace[newMat, {"nan" -> 0, _ -> 1}, {2}]
(* {0.647029, 0.723874, 0.421168, 0.693475} *)
$\endgroup$
  • $\begingroup$ That doesn't give the mean of the remaining column entries. It gives the mean of the column where "nan" = 0. In other words, it looks like it's taken the mean of four entries. $\endgroup$ – Sultan of Swing Oct 30 '14 at 21:55
  • $\begingroup$ @LonelyMathematician I divide by the number of not-"nan" elements so it is the mean of not-"nan" elements. $\endgroup$ – ybeltukov Oct 31 '14 at 18:50
  • $\begingroup$ (0.313636+0.907441+0.141872)/3 = 0.45431633333 != 0.340737 but (0.313636+0.907441+0.141872)/4 = 0.34073725. Looks to me like you still divided it by four, even though there are three elements in that column, since we don't count the "nan" entry. $\endgroup$ – Sultan of Swing Oct 31 '14 at 22:59
  • $\begingroup$ @LonelyMathematician Sorry, I made a mistake in level specification in Replace. Now it should work correctly. $\endgroup$ – ybeltukov Nov 1 '14 at 10:46
0
$\begingroup$
n = 4;
m = RandomReal[1, {n, n}];

Dynamic@TableForm@m

enter image description here

Do[
 m = Partition[#, n] & @ ReplacePart[Flatten[m], 
                                     Thread[RandomSample[Range[n^2], n - 1] -> "NAN"]];
 Pause@.1;

 m = Composition[
    Transpose,
    # /. col : {___, "NAN", ___} :> (col /. "NAN" :> Mean[DeleteCases[col, "NAN"]]) &,
    Transpose
    ]@m;

 Pause@.1
 ,
 {15}]
$\endgroup$
  • $\begingroup$ I'm sorry I don't follow this at all. I think you've created a matrix and you proceed to replace n-1 elements? with "NAN" which is great and you then find the mean of each column having deleted cases with "NAN". But the problem is you're using a Do loop (which I can't use) and the code doesn't actually output anything. This gives me some good ideas but the actual answer isn't very descriptive. $\endgroup$ – Sultan of Swing Oct 30 '14 at 10:45
  • $\begingroup$ @LonelyMathematician Do is only in order to repeate it. Single procedure have no loops. p.s. you can see what is happening if you evaluate Dynamic.... from the first code block. $\endgroup$ – Kuba Oct 30 '14 at 10:56
  • $\begingroup$ OH I'm so sorry! I deleted the Dynamic part! I'm really sorry about that. I'll take a look tomorrow; thanks! $\endgroup$ – Sultan of Swing Oct 30 '14 at 10:58
0
$\begingroup$
SeedRandom[42];
mat = RandomReal[{0, 1}, {4, 4}];
pos = RandomSample[Join @@ MapIndexed[#2 &, mat, {2}], 3];
(* {{3, 4}, {4, 2}, {1, 4}} *)

mat2 = MapAt["nan" &, mat, pos];
mat3 = ReplacePart[mat, pos -> "nan"];
mat4 = mat; (mat4[[##]] = "nan") & @@ # & /@ pos;

Equal @@ {mat2, mat3, mat4}
(* True *)

mat2b = Transpose[Replace[Transpose@mat2, {v__} /; ! FreeQ[{v}, "nan"] :>
            ({v} /. "nan" -> (Total[#]/Length[#] &[DeleteCases[{v}, "nan"]])), 2]];

TableForm[MatrixForm /@ (MapAt[Style[#, Red] &, #, pos] & /@ {mat, mat2, mat2b}),
         TableHeadings -> {{"mat", "mat2", "mat2b"}, None}, TableSpacing -> 5]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.