Adding a column is as simple as assigning to a new key: df['new'] = df['a'] + df['b']. To remove one, use df.drop('col', axis=1) or the in-place shortcut del df['col']. Renaming is handled by df.rename(columns={'old': 'new'}, inplace=True), which also accepts a function for bulk renames — df.rename(columns=str.lower) lowercases every column. When the dtype of a column needs to change, df['col'] = df['col'].astype(int) converts it; common targets include int, float, str, the memory-efficient 'category', and the time-aware datetime64[ns].
Many DataFrame methods return a new frame rather than mutating the existing one. The parameter inplace=True tells the method to modify df directly — for example, df.drop('col', axis=1, inplace=True). Without it, you rebind the name: df = df.drop('col', axis=1). Both produce the same observable result, but only one keeps the original object identity. Knowing this distinction avoids subtle bugs, especially when chained indexing could trigger a SettingWithCopyWarning.
Sorting and reindexing control the order of rows. df.sort_values('col') orders by a column, with ascending=False flipping the direction; passing a list such as df.sort_values(['a', 'b'], ascending=[True, False]) sorts by multiple keys with independent directions. df.sort_index() instead sorts by the row index. To discard the current index and replace it with the default integer range, use df.reset_index(drop=True); the drop=True flag throws the old index away. Conversely, df.set_index('col') promotes an existing column to the index, which is especially useful for time-series work where the index becomes a DatetimeIndex.