Your experiments show that 2-opt could outperform 3-opt. The reason is that there are many local optima, and some of the are better than others. Local search guarantees reaching a local optimum with respect to the moves being considered, but it doesn't provide any guarantee beyond that. It could be that one point which is locally optimal with respect to 2-opt is better than another point which is locally optimal with respect to 3-opt.
You can modify your algorithm to first try local search with respect to 2-opt and then with respect to 3-opt, and take the better solution. You could improve this by running a 3-opt local search starting at the 2-opt local minimum.
There are other degrees of freedom in the local search algorithm: for example, when there are several possible local improvements, which do you choose? A uniformly random one? The first one you found? The one which results in the best improvement? A random one chosen in proportion to the improvement? And so on. Each of these could result in a different solution. If you use a randomized strategy, each single run using the same heuristic could result in a different solution, so it makes sense to run local search many times.
An even more drastic option would be to replace local search with simulated annealing, which sometimes allows taking a local change which worsens the situation a bit. This might fare better on some instances.