Segue uma possivel solução com o aggregate, mas ele faz exatamente a mesma coisa que o tapply, so mudam os argumentos.
> temp1<-aggregate(x=d1$acidezKOH, by=list(d1$Tipo,d1$Trat,d1$Tempo), FUN=mean)
> temp2<-aggregate(x=d1$acidezOLEIC, by=list(d1$Tipo,d1$Trat,d1$Tempo), FUN=mean)
> dmedia<-data.frame(temp1,temp2[,4])
> colnames(dmedia)
[1] "Group.1" "Group.2" "Group.3" "x" "temp2...4."
> colnames(dmedia)<-c("Tipo","Trat","Tempo","acidezKOH", "acidezOLEIC")
> head(dmedia)
Tipo Trat Tempo acidezKOH acidezOLEIC
1 TI1 TR1 0 2.320000 1.1666667
2 TI2 TR1 0 0.230000 0.1100000
3 TI3 TR1 0 0.090000 0.0400000
4 TI1 TR2 0 3.533333 1.7733333
5 TI2 TR2 0 0.270000 0.1333333
6 TI3 TR2 0 0.140000 0.0700000
> class(dmedia)
[1] "data.frame"
Vai existir muitas formas de isso, alguma provavelmente mais rápidas, mas assim eu so calculei as médias guardando em dois objetos temporariors, depois eu coloquei tudo num dataframe e modifiquei os nomes das colunas para ficar bonitinho. Ja da para quebrar o galho.