Как сделать условное сложное «объединение» двух столбцов в pandas DataFrame? - PullRequest
2 голосов
/ 19 июня 2020

У меня есть pandas DataFrame df:

cit1   cgen1   cit2   cgen2   pair1   pair2

c1     male    c25    female  A       B        (+)
c2     female  c25    female  A       B
c5     male    c25    female  A       B
c5     male    c26    male    A       B

c1     male    c1     male    A       C        (*)
c2     female  c3     female  A       C

c1     male    c13    male    C       D
c7     female  c13    male    C       D
c8     male    c17    female  C       D

c8     male    c17    female  E       F
c12    male    c17    female  E       F
...

(обратите внимание, что пустое пространство вставлено произвольно для удобства читателей)

Здесь для упрощения понимание, рассматривать cit1 и cgen1 как пару, cit2 и cgen2 как пару, а pair1 и pair2 как пару.

Мой желаемый результат DataFrame df2 выглядит следующим образом:

cit    cgen    pair1    pair2

c1     male    A        B         (&)
c2     female  A        B
c5     male    A        B
c25    female  A        B         (&&)
c26    male    A        B

c1     male    A        C
c2     female  A        C
c3     female  A        C

c1     male    C        D
c7     female  C        D
c8     male    C        D
c13    male    C        D
c17    female  C        D

c8     male    E        F
c12    male    E        F
c17    female  E        F
...

По сути, я хочу сформировать объединенные столбцы cit и cgen, объединив cit1 и cit2 (для cit) и соответствующие cgen1 и cgen2 (для cgen) на уникальную пару значений pair1 и pair2.

Например, c1 и male из cit1 и cgen1 в (+) зарегистрированы как cit и cgen в (&).

c25 и female из cit2 и cgen2 в (+) зарегистрированы как cit и cgen в (&&).

Существуют также некоторые случаи, когда cit1 == cit2 для определенной пары, отображаемой (*).

Я пробовал разные функции, например pandas.merge(), pandas.concat() и pandas.groupby(), но ничего такого emed производить то, что я собираюсь производить. (Я не обязательно буду писать здесь проверенные коды, поскольку все они приводят к бессмыслице. При необходимости я могу добавить это в комментарии по запросу.)

Любые идеи о том, как решить эту проблему, будут приветствоваться.

Ответы [ 3 ]

2 голосов
/ 19 июня 2020

Используйте wide_to_long для изменения формы, затем удалите дубликаты по DataFrame.drop_duplicates, отсортируйте по DataFrame.sort_values и создайте индекс по умолчанию:

df = (pd.wide_to_long(df.reset_index(), stubnames=['cit','cgen'], i='index', j='tmp')
        .reindex(['cit','cgen','pair1','pair2'], axis=1)
        .drop_duplicates(["pair1", "pair2", "cgen", "cit"])
        .sort_values(["pair1", "pair2", "cit"], ignore_index=True)
        .reset_index(drop=True)
        )
print (df)
    cit    cgen pair1 pair2
0    c1    male     A     B
1    c2  female     A     B
2   c25  female     A     B
3   c26    male     A     B
4    c5    male     A     B
5    c1    male     A     C
6    c2  female     A     C
7    c3  female     A     C
8    c1    male     C     D
9   c13    male     C     D
10  c17  female     C     D
11   c7  female     C     D
12   c8    male     C     D
13  c12    male     E     F
14  c17  female     E     F
15   c8    male     E     F

Или вы можете rename столбцов отфильтровать по подмножеству, объединить по concat, удалить дубликаты и отсортировать:

d = {'cit1':'cit','cit2':'cit','cgen1':'cgen','cgen2':'cgen'}
df = (pd.concat([df[['cit1','cgen1','pair1','pair2']].rename(columns=d),
                df[['cit2','cgen2','pair1','pair2']].rename(columns=d)])
        .drop_duplicates(["pair1", "pair2", "cgen", "cit"])
        .sort_values(["pair1", "pair2", "cit"], ignore_index=True))
print (df)
    cit    cgen pair1 pair2
0    c1    male     A     B
1    c2  female     A     B
2   c25  female     A     B
3   c26    male     A     B
4    c5    male     A     B
5    c1    male     A     C
6    c2  female     A     C
7    c3  female     A     C
8    c1    male     C     D
9   c13    male     C     D
10  c17  female     C     D
11   c7  female     C     D
12   c8    male     C     D
13  c12    male     E     F
14  c17  female     E     F
15   c8    male     E     F
0 голосов
/ 19 июня 2020

Я уверен, что есть более идиоматический c способ, но я думаю, что это работает: разделить df на два DataFrames, один из которых соответствует «c1», а другой - «c2», но оба с одной парой столбцы. Затем concat:

df1 = df[['cit1','cgen1','pair1','pair2']]
df2 = df[['cit2','cgen2','pair1','pair2']]

df1.columns = ['cit','cgen','pair1','pair2']
df2.columns = ['cit','cgen','pair1','pair2']

output = pd.concat([df1,df2])

Но здесь есть дубликаты по сравнению с желаемым результатом, поэтому я удалил их. И кредит на ответ @jezrael b / c Я не понял, как был отсортирован вывод:

output = output[~output.duplicated()].sort_values(['pair1','pair2','cit']).reset_index(drop=True)

Результат:

    cit    cgen pair1 pair2
0    c1    male     A     B
1    c2  female     A     B
2   c25  female     A     B
3   c26    male     A     B
4    c5    male     A     B
5    c1    male     A     C
6    c2  female     A     C
7    c3  female     A     C
8    c1    male     C     D
9   c13    male     C     D
10  c17  female     C     D
11   c7  female     C     D
12   c8    male     C     D
13  c12    male     E     F
14  c17  female     E     F
15   c8    male     E     F
0 голосов
/ 19 июня 2020

Установить пары в качестве индекса, создать мультииндекс из столбцов, стек самый низкий уровень, затем удалить дубликаты на основе пар, cgen и cit

df = df.set_index(["pair1", "pair2"])

df.columns = df.columns.str.split("(\d)", expand=True).droplevel(-1)
df.columns.names = names = ["text", "numbers"]

(
    df.stack()
    .reset_index()
    .drop_duplicates(["pair1", "pair2", "cgen", "cit"])
    .sort_values(["pair1", "pair2", "numbers"], ignore_index=True)
    .drop("numbers", 1)
)



text    pair1   pair2   cgen    cit
0        A          B   male    c1
1        A          B   female  c2
2        A          B   male    c5
3        A          B   female  c25
4        A          B   male    c26
5        A          C   male    c1
6        A          C   female  c2
7        A          C   female  c3
8        C          D   male    c1
9        C          D   female  c7
10       C          D   male    c8
11       C          D   male    c13
12       C          D   female  c17
13       E          F   male    c8
14       E          F   male    c12
15       E          F   female  c17
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...