user: How do you iterate over a python panda data frame?

assistant: Iteration in Pandas is an anti-pattern and is something you should only do when you have exhausted every other option. You should not use any function with "iter" in its name for more than a few thousand rows or you will have to get used to a lot of waiting.

Do you want to compute something? In that case, search for methods in this order:
    1. Vectorization
    2. Cython routines
    3. List Comprehensions
    4. DataFrame.apply()
    5. DataFrame.itertuples() and DataFrame.iteritems()
    6. DataFrame.iterrows()

iterrows and itertuples should be used in very rare circumstances, such as generating row objects/nametuples for sequential processing, which is really the only thing these functions are useful for.

A good number of basic operations and computations are "vectorized" by pandas (either through NumPy, or through Cythonized functions). This includes arithmetic, comparisons, (most) reductions, reshaping, joins, and groupby operations.

user: Can you give me a code example for each?

assistant: Sure! Here are code examples for each of the different iteration methods in Pandas:

Vectorized Operations:

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
df['col3'] = df['col1'] + df['col2']
print(df)
Cython routines:
Cython routines are functions written in Cython language, which is a superset of Python. You can write the most performance critical parts of your code in Cython and still call the Cython functions from Python code.
Here's an example of using Cython to add two columns:

import pandas as pd
import numpy as np
from cython import boundscheck, wraparound

@boundscheck(False)
@wraparound(False)
def cy_add_columns(double[:, :] df):
    cdef int n = df.shape[0]
    cdef int m = df.shape[1]
    cdef double[:, :] res = np.empty((n, m + 1), dtype=np.double)
    for i in range(n):
        for j in range(m):
            res[i, j] = df[i, j]
        res[i, m] = df[i, 0] + df[i, 1]
    return res

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
np_array = df.values
new_col = cy_add_columns(np_array)
df = pd.DataFrame(new_col, columns=['col1', 'col2', 'col3'])
print(df)


List Comprehensions:

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
df['col3'] = [x + y for x, y in zip(df['col1'], df['col2'])]
print(df)


DataFrame.apply():

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
df['col3'] = df.apply(lambda row: row['col1'] + row['col2'], axis=1)
print(df)


DataFrame.itertuples():

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
for row in df.itertuples():
    df.at[row.Index, 'col3'] = row.col1 + row.col2
print(df)


DataFrame.iterrows():

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
for index, row

Vectorization:

df['col3'] = df['col1'] + df['col2']


Cython routines: Not applicable, as this depends on the specific routine you want to use.

List Comprehensions:

df['col3'] = [x + y for x, y in zip(df['col1'], df['col2'])]


DataFrame.apply():

def add_cols(row):
    return row['col1'] + row['col2']
df['col3'] = df.apply(add_cols, axis=1)


DataFrame.itertuples():

col3 = []
for row in df.itertuples():
    col3.append(row.col1 + row.col2)
df['col3'] = col3


DataFrame.iterrows():

col3 = []
for index, row in df.iterrows():
    col3.append(row['col1'] + row['col2'])
df['