title: How to replace NA with mean by group / subset?
body: <p>I have a dataframe with the lengths and widths of various arthropods from the guts of salamanders. Because some guts had thousands of certain prey items, I only measured a subset of each prey type. I now want to replace each unmeasured individual with the mean length and width for that prey. I want to keep the dataframe and just add imputed columns (length2, width2). The main reason is that each row also has columns with data on the date and location the salamander was collected. I could fill in the NA with a random selection of the measured individuals but for the sake of argument let's assume I just want to replace each NA with the mean.</p>
  
  <p>For example imagine I have a dataframe that looks something like:</p>
  
  <pre><code>id    taxa        length  width
  101   collembola  2.1     0.9
  102   mite        0.9     0.7
  103   mite        1.1     0.8
  104   collembola  NA      NA
  105   collembola  1.5     0.5
  106   mite        NA      NA
  </code></pre>
  
  <p>In reality I have more columns and about 25 different taxa and a total of ~30,000 prey items in total. It seems like the plyr package might be ideal for this but I just can't figure out how to do this. I'm not very R or programming savvy but I'm trying to learn.</p>
  
  <p>Not that I know what I'm doing but I'll try to create a small dataset to play with if it helps.</p>
  
  <pre><code>exampleDF &lt;- data.frame(id = seq(1:100), taxa = c(rep("collembola", 50), rep("mite", 25), 
  rep("ant", 25)), length = c(rnorm(40, 1, 0.5), rep("NA", 10), rnorm(20, 0.8, 0.1), rep("NA", 
  5), rnorm(20, 2.5, 0.5), rep("NA", 5)), width = c(rnorm(40, 0.5, 0.25), rep("NA", 10), 
  rnorm(20, 0.3, 0.01), rep("NA", 5), rnorm(20, 1, 0.1), rep("NA", 5)))
  </code></pre>
  
  <p>Here are a few things I've tried (that haven't worked):</p>
  
  <pre><code># mean imputation to recode NA in length and width with means 
    (could do random imputation but unnecessary here)
  mean.imp &lt;- function(x) { 
    missing &lt;- is.na(x) 
    n.missing &lt;-sum(missing) 
    x.obs &lt;-a[!missing] 
    imputed &lt;- x 
    imputed[missing] &lt;- mean(x.obs) 
    return (imputed) 
    } 
  
  mean.imp(exampleDF[exampleDF$taxa == "collembola", "length"])
  
  n.taxa &lt;- length(unique(exampleDF$taxa))
  for(i in 1:n.taxa) {
    mean.imp(exampleDF[exampleDF$taxa == unique(exampleDF$taxa[i]), "length"])
  } # no way to get back into dataframe in proper places, try plyr? 
  </code></pre>
  
  <p>another attempt:</p>
  
  <pre><code>imp.mean &lt;- function(x) {
    a &lt;- mean(x, na.rm = TRUE)
    return (ifelse (is.na(x) == TRUE , a, x)) 
   } # tried but not sure how to use this in ddply
  
  Diet2 &lt;- ddply(exampleDF, .(taxa), transform, length2 = function(x) {
    a &lt;- mean(exampleDF$length, na.rm = TRUE)
    return (ifelse (is.na(exampleDF$length) == TRUE , a, exampleDF$length)) 
    })
  </code></pre>
  
  <p>Any suggestions?</p>