Disclaimer: MySQL specifically warns against what I'm about to do. You can't rely on it to work forever as it depends on the behavior of the server and how it executes the query.
User-defined variables. You need to execute two statements, with the added one to initialize variables.
For each row,
SET @num = 1, @pattern = 0, @grpname = "";
@num := IF(@pattern = aPattern.pattern AND @grpname = groups.grpname, @num + 1, 1) AS num,
names.name AS Name,
@pattern := aPattern.pattern AS Pattern,
@grpname := groups.grpname AS `Group`
LEFT JOIN ...
ORDER BY aPattern.pattern, groups.grpname, ...;
1. @num is set to either @num + 1 if the pattern and group match the previous (stored in @pattern and @grpname respectively), otherwise 1. This value is returned.
2. @pattern and @grpname are both set. Those values are also returned.
Notice that I changed the ORDER BY to go with the group name and not its id, as the ranking number varies with the name.
I think there's another more reliable method but I don't remember what it is. A third (or second) method is a temporary table that looks like
CREATE TEMPORARY TABLE example (
num INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (Pattern, `Group`, num)
and to use it
INSERT INTO example
SELECT NULL, names.name, aPattern.pattern, groups.grpname
SELECT * FROM example ORDER BY Pattern, `Group`, num