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$
3
  • 1
    $\begingroup$ RandomSample. DeleteCases. $\endgroup$ Oct 30, 2014 at 6:33
  • $\begingroup$ Something like this? flatMat = Flatten[mat] then flatMat /. {RandomSample[flatMat, 3] -> {"nan", "nan", "nan"}} $\endgroup$ Oct 30, 2014 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$ Oct 30, 2014 at 6:55

3 Answers 3

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$
4
  • $\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$ Oct 30, 2014 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, 2014 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$ Oct 31, 2014 at 22:59
  • $\begingroup$ @LonelyMathematician Sorry, I made a mistake in level specification in Replace. Now it should work correctly. $\endgroup$
    – ybeltukov
    Nov 1, 2014 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"]];
 [email protected];

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

 [email protected]
 ,
 {15}]
$\endgroup$
3
  • $\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$ Oct 30, 2014 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, 2014 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$ Oct 30, 2014 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 and acknowledge that you have read and understand our privacy policy and code of conduct.

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