A couple of suggestions for a little more generality; the `input` event could be used on the form itself, as it propagates the events down to the inputs. From there one can use the `HTMLFormElement` API to grab the sibling inputs and output.

Also when using the `input` event, it allows for the `<output>` elements to update on every change, and to show for example input errors in real-time.

For semantic markup, I would suggest using `<fieldset>` and `<legend>`, although they still suffer from getting special treatment from some browser vendors which can make styling difficult. I would also recommend using `<input type="number">`'s `min`, `max` and `step` attributes.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

 document.addEventListener('DOMContentLoaded', () => {
 const outputs = document.querySelectorAll('output')
 const using = (thing, fun) => fun(thing)

 const average = ary =>
 using(ary.map(x => Number(x.value)).filter(Boolean),
 xs => (xs.reduce((x, y) => x + y, 0) / xs.length).toFixed(1))
 const lastAsAverage = coll =>
 using([...coll], xs => xs.pop().value = average(xs))

 document.forms[0].addEventListener('input',
 ({target: {parentElement: {elements: inputs}}}) =>
 [inputs, outputs].forEach(lastAsAverage))
 })

<!-- language: lang-css -->

 input:invalid { background-color: #faa }

<!-- language: lang-html -->

 <form>
 <fieldset>
 <legend>Physics:</legend>
 <input type="number">
 <input type="number">
 <input type="number">
 <output></output>
 </fieldset>

 <fieldset>
 <legend>History:</legend>
 <input type="number">
 <input type="number">
 <input type="number">
 <output></output>
 </fieldset>

 <output></output>

 <input type="reset">
 </form>

<!-- end snippet -->