Question: I have a list of Data Frames, each corresponding to a different time period t from 0 to N. Each data frame has multiple types, I need to preform the calculation below for each type in the data frame. An example data set would be as follows, I made each df in the list the same values for simplicity but the calculation would remain the same. d = {'type': ['a', 'b', 'c'], 'x': [1, 2, 3], 'y':[3,4,5]} df = pd.DataFrame(data=d) l = [] window = 20 [l.append(df.copy(deep=True)) for i in range(window)]  I need to compute a vectored sum $$\sum$$ and product $$\prod$$ using the above list of dataframes for each type (a, b, c) in an efficient manner. e.g. for each calculation below I need to filter by a single type df[df['type'] == 'a'] for every df in the list.  If I use a df.groupby('type') on every df in the list it could be very slow using a larger data set. The same goes if I use nested for loops for the sum and the product and filtering by type in each iteration of the for loop. How can I compute this sum product in an efficient manner ? Update One possible way as suggested in the comments is below, however this will start to be very inefficient if I use a larger dataset or window: import pandas as pd import math d = {'type': ['a', 'b', 'c'], 'x': [1, 2, 3], 'y':[3, 4, 5]} df = pd.DataFrame(data=d) l = [] window = 20 for i in range(window): df['window'] = i l.append(df.copy(deep=True)) df = pd.concat(l) sums = {} types = df['type'].unique() for s in types: sums[s] = 0 tdf = df[df['type'] == s] for i in range(window): sums[s] += tdf[tdf['window'] == i]['x'].values[0] * math.prod(2 - tdf[tdf['window'] == i+1]['x'].values[0] for i in range(0, window-1)) * tdf[tdf['window'] == i]['y'].values[0] 

Answer: Assuming I've understood your intent correctly, you could try something along these lines. sums = {} x_col_idx = df.columns.get_loc('x') for s, tdf in df.groupby('type'): sums[s] = np.dot(tdf['x'], tdf['y']) * np.prod(2 - tdf['x'].iloc[1:])  This gets the same results on your example and a few other examples I tried as the reference code, and is much faster. It also mostly stays within Pandas.  EDIT: If you're willing to do the whole computation in Numpy, you can get a 3x speedup. (More, if you have a large number of groups.) However, this comes at the cost of the code being much harder to read. def run(): # Convert to numpy type_ = df['type'].values x = df['x'].values y = df['y'].values uniques, codes = np.unique(type_, return_inverse=True) # Set up intermediate arrays dot_prod = np.zeros(len(uniques)) per_type_prod = np.ones(len(uniques) + 1) # Compute dot product of x and y within each group prod = x * y np.add.at(dot_prod, codes, prod) # Compute (2 - x).prod() within each group, dropping first sample per_type_prod_before_multiply = 2 - x # Drop first instance of each type for i in range(len(uniques)): codes[(codes == i).argmax()] = -1 np.multiply.at(per_type_prod, codes, per_type_prod_before_multiply) # Last element is garbage, result of multiplying thrown away first element. per_type_prod = per_type_prod[:-1] # Convert to dictionary sums = {k: v for k, v in zip(uniques, per_type_prod * dot_prod)} return sums  This avoids df.groupby() by having an array for each of the N groups, and choosing which element to add into by the codes array.