I set up my DataFrame like so:
cols = ['molecule_id', 'atom_id', 'atom_type', 'x', 'y', 'z']
data = pd.DataFrame()\
.from_dict(data_dict, orient='index', columns=cols)\
.set_index(['molceule_id', 'atom_id'])
print(data.head(8))
Here data_dict: dict[str, list]
It results in:
atom_type x y z
molecule_id atom_id
0 0 C -2.893477 -2.893477 -2.893477
1 S -3.293477 -2.893477 -2.893477
1 0 C -2.893477 -1.736086 -1.736086
1 S -3.293477 -1.736086 -1.736086
2 0 C -1.736086 -2.893477 -1.736086
1 S -2.136086 -2.893477 -1.736086
3 0 C -1.736086 -1.736086 -2.893477
1 S -2.136086 -1.736086 -2.893477
Later in the code, I need to remove a molecule (say #1) from this frame, thus I do:
data.drop(labels=1, level='molecule_id', axis=0, inplace=True)
atom_type x y z
molecule_id atom_id
0 0 C -1.736086 -2.893477 -1.736086
1 S -2.136086 -2.893477 -1.736086
2 0 C -2.893477 -2.893477 -2.893477
1 S -3.293477 -2.893477 -2.893477
3 0 C -2.893477 -1.736086 -1.736086
1 S -3.293477 -1.736086 -1.736086
4 0 C -1.736086 -2.893477 0.578695
1 S -2.136086 -2.893477 0.578695
At this point, I would want to adjust 'molecule_id' index to achieve the desired output:
atom_type x y z
molecule_id atom_id
0 0 C -1.736086 -2.893477 -1.736086
1 S -2.136086 -2.893477 -1.736086
1 0 C -2.893477 -2.893477 -2.893477
1 S -3.293477 -2.893477 -2.893477
2 0 C -2.893477 -1.736086 -1.736086
1 S -3.293477 -1.736086 -1.736086
3 0 C -1.736086 -2.893477 0.578695
1 S -2.136086 -2.893477 0.578695
Upon setting an index Pandas seem to create FrozenList, thus I could not do something like:
data.index.levels[0] = new_id_level
The solution I have in mind is to rebuild MultiIndex from scratch and apply to the DataFrame with set_index():
atoms_per_molecule = 2
num_molecules = len(data)//atoms_per_molecule
molecule_id = np.repeat(range(num_molecules), atoms_per_molecule)
atom_id = np.tile(range(atoms_per_molecule), num_molecules)
tuples = list(zip(molecule_id, atom_id))
names = ['molecule_id', 'atom_id']
multi_id = pd.MultiIndex.from_tuples(tuples, names=names)
data.set_index(multi_id, inplace=True)
It works well but seems unreasonably complicated considering the number of drops I plan to perform.
Therefore, I am wondering if there are any other and more efficient ways to do so?
P.S: Maybe it is possible to create some kind of resettable index using a given pattern?