函数f(x,y)
,它接受两个Pandas Series并返回一个浮点数。我想将f
应用于DataFrame D
中的每对列,并构造返回值的另一个DataFrame E
,以便f(D[i],D[j])
是{的值i
{1}}行和j
列。直接的解决方案是在所有列对上运行嵌套循环:
E = pd.DataFrame([[f(D[i], D[j]) for i in D] for j in D],
columns=D.columns, index=D.columns)
但是,是否有更优雅的解决方案可能不涉及显式循环?
NB 这个问题不是this的愚蠢,尽管名称相似。
编辑玩具示例:
D = pd.DataFrame([[1,2,3], [4,5,6], [7,8,9]], columns=("a","b","c"))
def f(x,y): return x.dot(y)
E
# a b c
#a 66 78 90
#b 78 93 108
#c 90 108 126
答案 0 :(得分:1)
您可以使用Numpy's broadcasting来避免显式循环。
结合np.vectorize()
和显式签名,可以为我们提供以下内容:
vf = np.vectorize(f, signature='(n),(n)->()')
result = vf(D.T.values, D.T.values[:, None])
注释:
print(f'x:\n{x}\ny:\n{y}\n')
),以使自己确信自己在做正确的事情。f()
是对称的;如果不是(例如def f(x, y): return np.linalg.norm(x - y**2)
),则该参数会在广播问题上扩展一个维度。使用上面的表达式,您将得到与r E
相同的结果。相反,如果您使用result = vf(D.T.values[:, None], D.T.values)
,则会得到它的转置。df = pd.DataFrame(result, index=D.columns, columns=D.columns)
顺便说一句,如果f()
确实是您的玩具示例中的那个,我敢肯定,您可以直接写:
df = D.T.dot(D)
性能:
在性能方面,使用广播和矢量化的速度大约是10倍(在各种矩阵大小上都是稳定的)。相比之下,D.T.dot(D)
的尺寸(分别为100、100)要快700倍以上,但关键的是,似乎相对的速度在尺寸更大的情况下甚至更高(在我的测试中,尺寸(200、200, 1000)导致1M循环)。因此,像往常一样,强烈希望尝试找到一种使用现有的numpy函数来实现函数f()
的方法!