数据帧中所有可能的列组合 - pandas / python

11
我试图从一个数据框中创建另一个数据框,包含所有列之间的可能组合以及相应值之间的差异,例如在4月11日时,AB列应为(B-A)=0等。例如,从以下数据开始。
        Dt              A           B           C          D
        11-apr          1           1           1          1
        10-apr          2           3           1          2

我该如何获得一个外观如下的新框架:

desired result

我看到了下面的帖子,但是没能将其转换为适用于列的代码。

使用 Pandas 聚合所有数据框行对组合


有没有关于如何在三列中完成这个任务的想法?比如说,在上面的例子中我想要执行2*B - A - C? - S.Peters
4个回答

18

您可以使用:

from itertools import combinations
df = df.set_index('Dt')

cc = list(combinations(df.columns,2))
df = pd.concat([df[c[1]].sub(df[c[0]]) for c in cc], axis=1, keys=cc)
df.columns = df.columns.map(''.join)
print (df)
        AB  AC  AD  BC  BD  CD
Dt                            
11-apr   0   0   0   0   0   0
10-apr   1  -1   0  -2  -1   1

谢谢,这个完美地运作。你有没有想过如何将其修改为3种组合,例如ABC、ABD、BCD等,然后不是(B-A)而是2 * B - C - A? - S.Peters
1
你认为 cc = list(combinations(df.columns,3)) 合适吗? - jezrael
然后是 df.columns = df.columns.map('-'.join) - jezrael
嗯,所以需要 df = pd.concat([2 * df[c[2]] - df[c[1]] - df[c[0]] for c in cc], axis=1, keys=cc),对吧? - jezrael
1
我该如何对所有更多的变量(更多的组合)执行相同的操作,并将数字(或字符串)相加而不是相减呢?例如:A B C D E AB AC AD ..... ABCDE ? @jezrael - constiii
显示剩余2条评论

9

请确保您的索引是 Dt

df = df.set_index('Dt')

使用 numpynp.tril_indices 和切片操作。 有关 np.triu_indices 的说明,请参见下面。
v = df.values

i, j = np.tril_indices(len(df.columns), -1)

我们可以为列创建一个 `pd.MultiIndex`。这样更适用于列名超过一个字符的情况。
pd.DataFrame(
    v[:, i] - v[:, j],
    df.index,
    [df.columns[j], df.columns[i]]
)

        A     B  A  B  C
        B  C  C  D  D  D
Dt                      
11-apr  0  0  0  0  0  0
10-apr  1 -1 -2  0 -1  1

但我们也可以这样做。
pd.DataFrame(
    v[:, i] - v[:, j],
    df.index,
    df.columns[j] + df.columns[i]
)

        AB  AC  BC  AD  BD  CD
Dt                            
11-apr   0   0   0   0   0   0
10-apr   1  -1  -2   0  -1   1

np.tril_indices 解释

np.tril_indices 是一个 numpy 函数,它返回两个数组,这两个数组结合使用可以提供一个方阵的下三角位置。当对一些东西的所有组合进行操作时,这非常方便,因为该下三角代表矩阵的一个轴与另一个轴的所有组合。

考虑数据帧 d 作为示例

d = pd.DataFrame(np.array(list('abcdefghijklmnopqrstuvwxy')).reshape(-1, 5))
d

   0  1  2  3  4
0  a  b  c  d  e
1  f  g  h  i  j
2  k  l  m  n  o
3  p  q  r  s  t
4  u  v  w  x  y

三角形的索引,当看作坐标对时,如下所示。
i, j = np.tril_indices(5, -1)
list(zip(i, j))

[(1, 0),
 (2, 0),
 (2, 1),
 (3, 0),
 (3, 1),
 (3, 2),
 (4, 0),
 (4, 1),
 (4, 2),
 (4, 3)]

我可以通过使用ij来操纵d的值。
d.values[i, j] = 'z'
d

   0  1  2  3  4
0  a  b  c  d  e
1  z  g  h  i  j
2  z  z  m  n  o
3  z  z  z  s  t
4  z  z  z  z  y

你可以看到它只针对那个下三角形进行了定位。

朴素时间测试

在这里输入图片描述


1
< p > Itertools模块将帮助您创建所需的组合/排列。 < /p >
from itertools import combinations

# Creating a new pd.DataFrame
new_df = pd.DataFrame(index=df.index)

# list of columns
columns = df.columns

# Create all combinations of length 2 . eg. AB, BC, etc.
for combination in combinations(columns, 2):
    combination_string = "".join(combination)
    new_df[combination_string] = df[combination[1]]-df[combination[0]]
    print new_df


         AB  AC  AD  BC  BD  CD
Dt                            
11-apr   0   0   0   0   0   0
10-apr   1  -1   0  -2  -1   1

1
虽然比上面Languitar的答案慢,但这个更易读。感谢@Nipun提供出色的解答。 - veg2020

1
"

itertools.combinations将对您有所帮助:

"
import itertools
pd.DataFrame({'{}{}'.format(a, b): df[a] - df[b] for a, b in itertools.combinations(df.columns, 2)})

这会导致:
        AB  AC  AD  BC  BD  CD
Dt                            
11-apr   0   0   0   0   0   0
10-apr  -1   1   0   2   1  -1

1
如果您有其他条件,例如df = pd.DataFrame({'{}{}'.format(a, b): df[a] & df[b] for a, b in itertools.combinations(df.columns, 2) if (df[a] & df[b]).any() }),这个方法非常有效。与之前的答案不同,列标签不会混乱。 - user11186769

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接