Пересечение / подмножество столбцов строк панд - PullRequest
1 голос
/ 10 июня 2019

У меня есть фрейм данных pandas с платежами следующей структуры:

>> print(df)

id      time      amount      seller     buyer
-------------------------------------------------
1       07:01     16.00       Jack       Rose
2       07:03     14.00       Alice      Bob
3       07:05     95.00       Jim        Larry
...     ...       ...         ...        ...
9999    18:16     81.00       Rose       Alice

Как найти из этого сеть платежей "закрытых членов"?

Например, если я хотел бы найти подмножество данных, которое содержит только платежи, которые {Роза, Алиса, Джим} совершали строго между собой, тогда может работать следующее:

members = ['Rose', 'Alice', 'Jim']
df_subset = df[df.seller.isin(members) & df.buyer.isin(members)]

Но как получить наибольшую такую ​​сеть? То есть не только для 3 человек, но и для максимально возможного числа людей в кадре данных?

Я уже пробовал варианты ниже:

df_subset = df[df.seller.isin(df.buyer.unique())]
df_subset = df_subset[df_subset.buyer.isin(df_subset.seller.unique())]

Однако это не удачно, поскольку впоследствии df_subset.seller.unique() и df_subset.buyer.unique() не совпадают.

Любая помощь будет оценена.

Полагаю, в конце df_subset.seller.unique() и df_subset.buyer.unique() должны быть одинаковыми.

Ответы [ 3 ]

0 голосов
/ 11 июня 2019

IIUC, следующее должно делать то, что вы хотите:

common_users = set(df["buyer"]).intersection(df["seller"])
df_subset = df[df["buyer"].isin(common_users) & df["seller"].isin(common_users)]
0 голосов
/ 11 июня 2019

Кажется, работает следующее решение.Я предоставлю решение «песочницы», так как оно может стать полезным для других.

Сначала давайте определим такой же фрейм данных панд, как в вопросе:

# generates strings to be used as names, e.g.: 'hlddldxhys'
def randomString(stringLength=10):
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(stringLength))

# let's generate a set of 600 names
participants = [];
for k in range(600):
    participants.append(randomString())

# from the generated set, draw 1000 sellers and buyers
seller = np.random.choice(participants, 1000)
buyer = np.random.choice(participants, 1000)

# construct pandas data frame
df = pd.DataFrame([seller, buyer]).T
df.columns = ['seller', 'buyer']

Рассмотрим итоговый фрейм данных.print(df):

     seller       buyer
----------------------------
0    bpzroghaxp  evvhhlbiys
1    qsopxbirgn  lwwljadfwg
2    cnllyrzjiz  opbvoodpgw
3    hkzafylzst  slfqtwdeak
...    ...        ...
999  natqsscnlk  ftvjvgtala

Хотя некоторые намекают на решение (ответы PMende, Tal Avissar и меня), похоже, что оно работает - но только итеративно , гдес каждой итерацией df = df[df.seller.isin(df.buyer.unique()) & df.buyer.isin(df.seller.unique())] множества df.seller.unique() и df.buyer.unique() становятся все более похожими друг на друга.Это повторяется до тех пор, пока они оба не будут одинаковыми (см. Последний оператор if, за которым следует break):

while(True):
    df = df[df.seller.isin(df.buyer.unique()) & df.buyer.isin(df.seller.unique())]
    if len(df.seller.unique()) == len(df.buyer.unique()):
        if (np.sort(df.seller.unique()) == np.sort(df.buyer.unique())).all() == True:
            break

Окончательная проверка подтверждает, что df.seller.unique() и df.buyer.unique() имеют одинаковую длину итакже того же состава:

>> len(df.seller.unique()), len(df.buyer.unique())
(281, 281)

>> (np.sort(df.seller.unique()) == np.sort(df.buyer.unique())).all()
True

Ниже на диаграммах показано, как наборы df.seller.unique() и df.buyer.unique() становятся похожими друг на друга с каждой итерацией цикла:

См.также графики: визуализация решения

0 голосов
/ 10 июня 2019

Это то, что вы ищете в максимальном количестве людей

a = df[df.seller].drop_duplicates()
b = df[df.buyer].drop_duplicates()
result = pd.concat([a,b])
...