如何将含x/y/z列的pandas DataFrame按行转为可运算向量
解决方案
不需要逐行拆分DataFrame生成独立Python列表向量,直接用numpy向量化运算处理是效率最高、代码最简洁的方案,逐行遍历、apply/lambda逐行处理的写法不仅冗余,数据量大时性能会差很多。
你提取的坐标数组天然支持所有向量、矩阵运算,完全满足笛卡尔转球坐标、旋转、转回笛卡尔坐标的需求,全流程不需要写显式for循环。
完整实现代码
import pandas as pd import numpy as np # 原始坐标数据 data = [[7.68, -0.3, -98.55],[7.59, 1.20, -99.26],[7.69, -0.2, -97.23],[6.98, 1.32, -98.98]] # 构造DataFrame,如果你原始输入是字符串列表,再做astype转换即可 atomdata = pd.DataFrame(data, columns=['x','y','z']) # 1. 提取所有坐标为形状(n,3)的numpy数组,每一行对应一个(x,y,z)向量 coords = atomdata[['x','y','z']].to_numpy() # 2. 笛卡尔坐标转球坐标 def cart2sph(cart_coords): x, y, z = cart_coords[:,0], cart_coords[:,1], cart_coords[:,2] r = np.sqrt(x**2 + y**2 + z**2) elev = np.arcsin(z / r) # 俯仰角,范围[-π/2, π/2] azim = np.arctan2(y, x) # 方位角,范围[-π, π] return np.stack([r, elev, azim], axis=1) # 3. 球坐标下按指定轴旋转theta角(theta单位为弧度) def rotate_sph(sph_coords, theta, axis='z'): r, elev, azim = sph_coords[:,0], sph_coords[:,1], sph_coords[:,2] if axis == 'z': azim += theta elif axis == 'x': new_elev = np.arcsin(np.sin(elev)*np.cos(theta) + np.cos(elev)*np.sin(azim)*np.sin(theta)) new_azim = np.arctan2( np.cos(elev)*np.sin(azim)*np.cos(theta) - np.sin(elev)*np.sin(theta), np.cos(elev)*np.cos(azim) ) elev, azim = new_elev, new_azim elif axis == 'y': new_elev = np.arcsin(np.sin(elev)*np.cos(theta) - np.cos(elev)*np.cos(azim)*np.sin(theta)) new_azim = np.arctan2( np.cos(elev)*np.sin(azim), np.cos(elev)*np.cos(azim)*np.cos(theta) + np.sin(elev)*np.sin(theta) ) elev, azim = new_elev, new_azim return np.stack([r, elev, azim], axis=1) # 4. 球坐标转回笛卡尔坐标 def sph2cart(sph_coords): r, elev, azim = sph_coords[:,0], sph_coords[:,1], sph_coords[:,2] x = r * np.cos(elev) * np.cos(azim) y = r * np.cos(elev) * np.sin(azim) z = r * np.sin(elev) return np.stack([x, y, z], axis=1) # 调用示例:绕z轴旋转45度(π/4弧度) theta = np.pi/4 sph_coords = cart2sph(coords) rotated_sph = rotate_sph(sph_coords, theta, axis='z') rotated_cart = sph2cart(rotated_sph) # 结果写回原DataFrame atomdata[['x_rot', 'y_rot', 'z_rot']] = rotated_cart
补充说明
- 如果你确实需要逐行取出单独向量做自定义处理,直接遍历numpy数组即可:
for vec in coords:每次循环拿到的就是长度为3的一维数组,对应单行x/y/z值,直接支持各类向量运算。 - 不建议用逐行
apply+lambda的方式处理坐标运算,numpy向量化操作的速度比逐行apply快10~100倍,代码可读性也更高。 - 如果你原始的
ATOMS是字符串列表,只需要在构造DataFrame后做一次类型转换即可,不需要额外写循环逐行处理:atomdata = atomdata.astype({'x':float, 'y':float, 'z':float})
内容的提问来源于stack exchange,提问作者Landon Gaber
相关产品推荐
相关产品推荐

