基于 2 列合并和对齐列

Merge and align columns based on 2 columns

我有一个如下的 df:

ID  P1   P2   P3_1_A  P3_2_B   P4_1_A  P4_2_B
1   110  111   1        0       1       1
2   111  112   0        0       1       0
3   110  112   0        1       0       0
4   112  111   1        1       1       1

因此,P1 和 P2 有 3 个不同的值 110111112

P3 和 P4 列的数量始终相等(在上述情况下为 2),但可能因数据而异。

我想要一个结果数据框,其中所有 P3 值都与 P1 对齐,所有 P4 值都与 P2 对齐,列重命名,如下所示

ID   P     P_A   P_B
1    110    1     0
1    111    1     1
2    111    0     0
2    112    1     0
3    110    0     1
3    112    0     0
4    112    1     1
4    111    1     1

我知道如何合并 P1 和 P2 并到达 P 列,但不知道如何将 P3 和 P4 与 P1 和 P2 对齐并到达 P_1 和 P_2

您可以重命名 _ 个子字符串的列,因此可以将 ID 转换为索引并将所有值拆分为 MultiIndex,最后按 DataFrame.stack:[=19 重塑=]

df1 = df.rename(columns={'P1':'P3_','P2':'P4_'}).set_index('ID')
df1.columns = df1.columns.str.split('_', expand=True, n=1)
df1 = df1.stack(0).add_prefix('P').reset_index(level=1, drop=True).reset_index()
print (df1)
   ID    P  P1_A  P2_B
0   1  110     1     0
1   1  111     1     1
2   2  111     0     0
3   2  112     1     0
4   3  110     0     1
5   3  112     0     0
6   4  112     1     1
7   4  111     1     1

编辑:对于更通用的解决方案,可以提取不带双 _ 的列名称并传递给 set_index:

print (df)
   ID   P1   P2  P3_1_A  P3_2_B  P4_1_A  P4_2_B  A
0   1  110  111       1       0       1       1  9
1   2  111  112       0       0       1       0  7
2   3  110  112       0       1       0       0  8
3   4  112  111       1       1       1       1  7

df1 = df.rename(columns={'P1':'P3__','P2':'P4__'})

cols = df1.columns[df1.columns.str.count('_') != 2]
df1 = df1.set_index(cols.tolist())
df1.columns = df1.columns.str.split('_', expand=True, n=1)
df1 = df1.stack(0).add_prefix('P').reset_index(level=-1, drop=True).reset_index()
print (df1)
   A  ID  P1_A  P2_B   P_
0  9   1     1     0  110
1  9   1     1     1  111
2  7   2     0     0  111
3  7   2     1     0  112
4  8   3     0     1  110
5  8   3     0     0  112
6  7   4     1     1  112
7  7   4     1     1  111

您可以使用 pivot_longer function from pyjanitor; at the moment you have to install the latest development version from github :

列具有模式(一些以数字(1 或 2)结尾,而另一些以 'A' 或 'B' 结尾)。我们可以利用这种模式并重塑数据。 我们将新列名列表传递给 names_to,并将与模式匹配的正则表达式列表传递给 names_pattern:

 # install the latest dev version of pyjanitor
 # pip install git+https://github.com/ericmjl/pyjanitor.git

 import janitor

df.pivot_longer(
    index="ID",
    names_to=("P", "P_A", "P_B"),
    names_pattern=("^P\d$", ".*A$", ".*B$"),
    sort_by_appearance=True,
)

   ID   P   P_A P_B
0   1   110 1   0
1   1   111 1   1
2   2   111 0   0
3   2   112 1   0
4   3   110 0   1
5   3   112 0   0
6   4   112 1   1
7   4   111 1   1

在上面的代码中,新的 P 列从具有列 P1 或 P2(它们以数字结尾)的先前数据框中获取所有值,P_A 获取以 'A',而 P_B 接受以 'B'.

结尾的列