 <p>Another option, that might be more flexible for future needs, is to use <code>dplyr</code>. This requires the data to be in a data.frame, but it sounds like that is what you have anyway.</p> <pre><code>df &lt;- data.frame(g, mat) df %&gt;% group_by(g) %&gt;% summarise_all(mean) </code></pre> <p>It groups by the <code>g</code> column, then takes a mean of all of the remaining columns. It returns:</p> <pre><code> g X1 X2 X3 1 a 1.5 7.5 13.5 2 b 3.5 9.5 15.5 3 c 5.5 11.5 17.5 </code></pre> <p>Which I believe is your desired outcome. If combined with <code>tidyr</code>, it may also make it easier to use/access those means by putting them in a long format</p> <pre><code>df %&gt;% gather(Measurement, Value, -g) %&gt;% group_by(g, Measurement) %&gt;% summarise(mean = mean(Value)) </code></pre> <p>returning:</p> <pre><code> g Measurement mean 1 a X1 1.5 2 a X2 7.5 3 a X3 13.5 4 b X1 3.5 5 b X2 9.5 6 b X3 15.5 7 c X1 5.5 8 c X2 11.5 9 c X3 17.5 </code></pre>