def make_interactions(people, hh_id_col, p_type_col):
    two_fmt = '{}{}'.format
    three_fmt = '{}{}{}'.format
    two = []
    three = []
    two_perm_cache = {}
    three_combo_cache = {}

    for hh_id, df in people.groupby(hh_id_col, sort=False):
        hh_size = len(df)

        # skip households with only one person
        if hh_size == 1:
            continue

        ptypes = df[p_type_col].values
        hh_idx = df.index.values

        if hh_size in two_perm_cache:
            two_perms = two_perm_cache[hh_size]
        else:
            two_perms = list(itertools.permutations(np.arange(hh_size), 2))
            two_perm_cache[hh_size] = two_perms

        two.extend(
            (hh_idx[pA], two_fmt(*ptypes[[pA, pB]])) for pA, pB in two_perms)

        # now skip households with two people
        if hh_size == 2:
            continue

        if hh_size in three_combo_cache:
            three_combos = three_combo_cache[hh_size]
        else:
            three_combos = list(itertools.combinations(np.arange(hh_size), 3))
            three_combo_cache[hh_size] = three_combos

        three.extend(
            (hh_idx[p], three_fmt(*ptypes.take(idx)))
            for idx in three_combos
            for p in idx)

    if two:
        two_idx, two_val = zip(*two)
    else:
        two_idx, two_val = [], []

    if three:
        three_idx, three_val = zip(*three)
    else:
        three_idx, three_val = [], []

    return (
        pd.DataFrame({'interaction': two_val}, index=two_idx),
        pd.DataFrame({'interaction': three_val}, index=three_idx))
Make two Pandas DataFrames associating people IDs with two
dataset/ETHPy150Open UDST/activitysim/activitysim/cdap/cdap.py/make_interactions