 <p>We can <code>transform</code> the dataset to create another column with <code>after 1970</code> and <code>before 1970</code> values. This can be done by first creating a logical vector (<code>col1 &lt;= 1970</code>), adding 1 to it so that <code>TRUE</code> becomes 2 and <code>FALSE</code> as 1. Use that as numeric index to change the values to <code>after 1970</code> and <code>before 1970</code>. Then, we get the frequency of the subset of columns ('col2' and 'col3') with <code>table</code>. Finally, the proportion by row can be got with <code>prop.table</code> with <code>MARGIN</code> specified as 1.</p> <pre><code>prop.table(table(transform(mydata, col3=c("after 1970", "before 1970")[(col1&lt;=1970)+1L])[3:2]), 1) # col2 # col3 a b c # after 1970 0.4000000 0.4000000 0.2000000 # before 1970 0.5454545 0.1818182 0.2727273 </code></pre> <hr> <p>Or another option with <code>data.table</code></p> <pre><code>library(data.table) #convert the 'data.frame' to 'data.table' (`setDT(mydata)`) #create the "year" column based on 'col1' values setDT(mydata)[col1&lt;=1970, year:= "before 1970" ][is.na(year), year:= "after 1970"] #we can use `dcast` to change from long to wide format dcast(mydata, year~col2, length)[, .SD/sum(unlist(.SD)) , year] # year a b c #1: after 1970 0.4000000 0.4000000 0.2000000 #2: before 1970 0.5454545 0.1818182 0.2727273 </code></pre> <hr> <p>Or with <code>dplyr/tidyr</code></p> <pre><code>library(dplyr) library(tidyr) mydata %&gt;% mutate(year= ifelse(col1 &lt;= 1970, "before 1970", "after 1970")) %&gt;% group_by(year) %&gt;% mutate(n1=n()) %&gt;% group_by(col2,n1, add=TRUE) %&gt;% tally() %&gt;% ungroup() %&gt;% mutate(n=n/n1) %&gt;% select(-n1) %&gt;% spread(col2,n) </code></pre>