Optimal dividing of K people into N groups
Solution in pseudocode:

initialize collection of persons (e.g. an array): 
    - each person itself is described by its position in collection
    - each person itself contains collection of positions (e.g. an array) 
      that describe wished persons for the person to be grouped with
(example: persons = [[1,2], [0,2], [0,3], [0,2]])

initialize empty collection of groups (e.g. an array): 
    - each group itself is described by its position in collection
    - each group itself contains collection of positions (e.g. an array) 
      that describe grouped persons

initialize number of persons per group (example: 2)
initialize total group count to be number of persons divided by number of persons per group (example: 2)
initialize constraint c1 as: any group shouldn't exceed the number of persons per group
initialize constraint c2 as: group count shouldn't exceed the number of total group count
initialize constraint c3 as minimum required of wishes granted per person in any group, for the solution to be valid (example: 1)
[*]initialize dictionary of solutions, where key is a pair (persons, groups), and value is a solution or an empty value

call group(persons, groups)

procedure group(persons, groups):
    [*]if there is a pair (persons, groups) in dictionary of solutions
    [*] return that solution

    for each person (let's call it this-person)
        for each person among this-persons wishes (let's call it wished-person)
            if wished-person is already grouped in any of the groups
                if this-person can be grouped in the same group with wished-person, at the same time satisfying c1
                    set new-groups as groups with this-person grouped accordingly
                    set new-persons as persons without this-person
                else
                    nothing can be done with wished-person, so continue with the next wished-person
            else
                if both this-person and wished-person can be grouped in any group, at the same time satisfying c1 and c2
                    set new-groups as groups with this-person and wished-person grouped accordingly
                    set new-persons as persons without both this-person and wished-person
                else
                    nothing can be done with wished-person, so continue with the next wished-person

            if there are any other persons left in new-persons
                set possible-solution to recursive call, group(new-persons, new-groups)
                if possible-solution is not empty 
                    [*]add item to dictionary of solutions, key is the pair (persons, groups), value is possible-solution
                    return it as a solution
            else if all the groups satisfy c3
                return new-groups as the solution

    [*]add item to dictionary of solutions, key is the pair (persons, groups), value is empty
    return empty value


The decision tree will exhaust all the possible paths towards the solution. However, if you use dynamic programming you can improve the performance by avoiding the execution of already known paths. The dynamic-programming part is marked with [*] in pseudocode.

You might further improve the performance by preferring least-popular persons over most popular when grouping.

Here's a Python implementation in case anyone needs it: https://repl.it/@OzrenTkalcec/Dividing-of-K-people-into-N-groups

Disclaimer: I'm not a data scientist, but I like to solve puzzles like this one :)

HTH