Python pandas.DataFrame上的成对行操作矩阵

Python pandas.DataFrame上的成对行操作矩阵,python,pandas,numpy,dataframe,pairwise,Python,Pandas,Numpy,Dataframe,Pairwise,我想创建一个数据帧中所有行对的操作结果矩阵 下面是我想要的一个例子: df = pandas.DataFrame({'val': [ 2, 3, 5, 7 ], 'foo': ['f1', 'f2', 'f3', 'f4']}, index= ['n1', 'n2', 'n3', 'n4']) def op1(row1, row2): return row1['val'

我想创建一个数据帧中所有行对的操作结果矩阵

下面是我想要的一个例子:

df = pandas.DataFrame({'val':  [ 2,    3,    5,    7  ],
                       'foo':  ['f1', 'f2', 'f3', 'f4']},
                      index=   ['n1', 'n2', 'n3', 'n4'])

def op1(row1, row2):
    return row1['val']*row2['val']

def op2(row1, row2):
    return f"{row1['foo']}{row2['foo']}"

def apply_op_to_all_row_pairs(df, op):
    # what goes in here?

apply_op_to_all_row_pairs(df, op1)
#     n1  n2  n3  n4
# n1   4   6  10  14
# n2   6   9  15  21
# n3  10  15  25  35
# n4  14  21  35  49

apply_op_to_all_row_pairs(df, op2)
#         n1      n2      n3      n4
# n1  'f1f1'  'f1f2'  'f1f3'  'f1f4'
# n2  'f2f1'  'f2f2'  'f2f3'  'f2f4'
# n3  'f3f1'  'f3f2'  'f3f3'  'f3f4'
# n4  'f4f1'  'f4f2'  'f4f3'  'f4f4'
我见过很多依赖于计算距离矩阵的现有函数的解决方案,但我想要更通用的解决方案。
例如,
scipy.spatial.distance.pdist
执行我想要的格式,但只处理浮点数,不允许您按名称选择列(或者至少我不知道如何选择)。

您可以使用广播numpy操作:

v = df.val.values[:, None] * df.val.values
v

array([[ 4,  6, 10, 14],
       [ 6,  9, 15, 21],
       [10, 15, 25, 35],
       [14, 21, 35, 49]])

x = df.foo.values[:, None] + df.foo.values
x

array([['f1f1', 'f1f2', 'f1f3', 'f1f4'],
       ['f2f1', 'f2f2', 'f2f3', 'f2f4'],
       ['f3f1', 'f3f2', 'f3f3', 'f3f4'],
       ['f4f1', 'f4f2', 'f4f3', 'f4f4']], dtype=object) 
转换为数据帧非常简单,只需调用构造函数:

pd.DataFrame(x, df.index, df.index)

      n1    n2    n3    n4
n1  f1f1  f1f2  f1f3  f1f4
n2  f2f1  f2f2  f2f3  f2f4
n3  f3f1  f3f2  f3f3  f3f4
n4  f4f1  f4f2  f4f3  f4f4

这并没有以问题的形式完成函数,但它确实满足了我的要求。谢谢@蔡:听你这么说太好了!感谢您让我知道。为了澄清我最初的问题:一种单独定义行对操作的方法,每个行对操作都可以应用于数据帧。这与您给出的不同之处在于,函数定义(
foo+foo
)与广播混合在一起。完全分开的那一个很好,但对于我现在需要的,这是完全足够的。@Cai我理解你现在的要求。不幸的是,解耦成本很高,并且会导致性能大大降低。仅供参考。