在一个多索引的DataFrame,如何执行矩阵乘法的数据子集?



下面的代码是一个示例DataFrame。现在我需要把所有的XYZ放到位置下乘以一个旋转矩阵,比如绕Z旋转90度:[[1,0,0],[0,0,-1],[0,1,0]]

如何在不使用循环的情况下做到这一点?或者循环越少越好。提前谢谢。

index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]],
names=['year', 'Record'])
columns = pd.MultiIndex.from_product([['Point1', 'Point2'],['Position', 'Not-Important'], ['X', 'Y','Z']])
# mock some data
data = np.round(np.random.randn(4, 12), 1)
data[:, ::2] *= 10
data += 37
# create the DataFrame
hd = pd.DataFrame(data, index=index, columns=columns)
Point1                                         Point2
Position             Not-Important             Position             Not-Important
X     Y     Z             X     Y     Z        X     Y     Z             X     Y     Z
year Record
2013 1          26.0  38.1  42.0          35.0  37.0  37.2     35.0  36.9  28.0          37.2  58.0  37.0
2          42.0  36.4  36.0          36.5  43.0  35.4     28.0  36.3  60.0          35.5  41.0  37.3
2014 1          47.0  36.6  32.0          37.9  58.0  37.7     25.0  36.5  21.0          38.6  33.0  36.3
2          42.0  38.6  26.0          35.2  37.0  36.3     21.0  36.5  27.0          36.3  26.0  35.5

我们有了变换矩阵:

Z = np.array([[1,0,0],[0,0,-1],[0,1,0]])

每一行有两个点,但它也有不重要的值。我们用点的旋转矩阵和其他值的单位矩阵建立一个变换矩阵,使它们保持不变。

# I'm sure there is a more elegant way of doing this
ZZ = np.zeros((12,12))
ZZ[0:3,0:3] = Z
ZZ[3:6,3:6] = np.eye(3)
ZZ[6:9,6:9] = Z
ZZ[9:12,9:12] = np.eye(3)

现在我们准备旋转这些点:

hd.transform(lambda x: np.matmul(ZZ, x), axis=1)

DataFrame.transform将对每一行调用我们的函数(因为axis参数是1),并传递一个包含值的序列。我们的函数只是在变换矩阵和对应于原始DataFrame中的一行的向量之间进行矩阵乘法。


为了避免DataFrame.transform所做的迭代,在numpy中进行矩阵乘法并创建一个新的DataFrame

result = np.matmul(hd.to_numpy(), ZZ.T)
pd.DataFrame(result, index=index, columns=columns)

这大约快了20倍,对一些人来说可能更容易理解。

最新更新