Pandas equivalent to R expand()

Viewed 56

I have the following code in R:

 col1 = 'carrier'
 col2 = 'mode'

 a = tbl %>%
    select(sym(col1), sym(col2))

 tbl2 <- a %>%
    select(sym(col1), sym(col2)) %>%
    expand(!!!syms(c(col1, col2)))

This is the content of tbl:

    carrier mode
3   CRX     ALL
4   GLS     ALL
6   LSR     ALL
7   TFRC    ALL
8   UDS     ALL
11  UPS     GROUND
12  UPS     AIR2
13  UPS     AIR1
14  FEDEX   GROUND
15  FEDEX   AIR2
16  FEDEX   AIR1

And this is the final content of tbl2:

carrier  mode
CRX      AIR1
CRX      AIR2
CRX      ALL
CRX      GROUND
FEDEX    AIR1
FEDEX    AIR2
FEDEX    ALL
FEDEX    GROUND
GLS      AIR1
GLS      AIR2
GLS      ALL
GLS      GROUND
LSR      AIR1
LSR      AIR2
LSR      ALL
LSR      GROUND
TFRC     AIR1
TFRC     AIR2
TFRC     ALL
TFRC     GROUND
UDS      AIR1
UDS      AIR2
UDS      ALL
UDS      GROUND
UPS      AIR1
UPS      AIR2
UPS      ALL
UPS      GROUND

I can see very clearly what R expand() does, but I haven't found an equivalent in Pandas to do so.

3 Answers

You can check with merge , since we do have the method cross , you only need drop_duplicates before pass two columns join

new = df1[['carrier']].drop_duplicates().merge(df1[['mode']].drop_duplicates(),how='cross')

Are you looking for expand_grid from the pandas cookbook?

import itertools

def expand_grid(data_dict):
    rows = itertools.product(*data_dict.values())
    return pd.DataFrame.from_records(rows, columns=data_dict.keys())

expand_grid(tbl.to_dict(orient='list')).drop_duplicates()

One option is to use complete from pyjanitor; this includes combinations not previously present in the data:

# pip install pyjanitor
import pandas as pd
import janitor
df.complete('carrier', 'mode', sort=True)
 
   carrier    mode
0      CRX    AIR1
1      CRX    AIR2
2      CRX     ALL
3      CRX  GROUND
4    FEDEX    AIR1
5    FEDEX    AIR2
6    FEDEX     ALL
7    FEDEX  GROUND
8      GLS    AIR1
9      GLS    AIR2
10     GLS     ALL
11     GLS  GROUND
12     LSR    AIR1
13     LSR    AIR2
14     LSR     ALL
15     LSR  GROUND
16    TFRC    AIR1
17    TFRC    AIR2
18    TFRC     ALL
19    TFRC  GROUND
20     UDS    AIR1
21     UDS    AIR2
22     UDS     ALL
23     UDS  GROUND
24     UPS    AIR1
25     UPS    AIR2
26     UPS     ALL
27     UPS  GROUND

Another option, to get combination of all unique values, is to use expand_grid from pyjanitor - it is similar to pandas' merge with how=cross, with speed enhancements:

from janitor import expand_grid
others = {'carrier': df.carrier.unique(), 'mode': df['mode'].unique()}
expand_grid(others = others).droplevel(1,1)

   carrier    mode
0      CRX     ALL
1      CRX  GROUND
2      CRX    AIR2
3      CRX    AIR1
4      GLS     ALL
5      GLS  GROUND
6      GLS    AIR2
7      GLS    AIR1
8      LSR     ALL
9      LSR  GROUND
10     LSR    AIR2
11     LSR    AIR1
12    TFRC     ALL
13    TFRC  GROUND
14    TFRC    AIR2
15    TFRC    AIR1
16     UDS     ALL
17     UDS  GROUND
18     UDS    AIR2
19     UDS    AIR1
20     UPS     ALL
21     UPS  GROUND
22     UPS    AIR2
23     UPS    AIR1
24   FEDEX     ALL
25   FEDEX  GROUND
26   FEDEX    AIR2
27   FEDEX    AIR1
Related