kiwii
kiwii

Reputation: 63

Create new column filled with random elements based on a categorical column

I have a pandas dataframe that looks like this:

ID  Cat
87    A 
56    A 
67    A  
76    D  
36    D 

Column ID has unique integers, while Cat contains categorical variables. Now I would like to add two new columns with conditions about Cat.

The desirable result should look like this:

ID  Cat  New1   New2
87    A    67    36
56    A    67    76
67    A    56    36
76    D    36    56
36    D    76    67

Column New1: for each row, pick a random ID with the SAME category as the current row ID, with replacements. The randomly picked ID should not be the same as the current row ID.

Column New2: for each row, pick a random ID with a DIFFERENT category than the current row ID, with replacements.

How can I do this efficiently?

Upvotes: 3

Views: 614

Answers (2)

Ethan
Ethan

Reputation: 1373

My previous answer did not correctly generate the column "new1". Understanding that a valid solution has been posted and accepted, I am posting this to offer an alternative.

df = pd.DataFrame.from_dict({'ID':(87,56,67,76,36),'CAT':('A','A','A','D','D')})
df['New1'] = [np.random.choice(df[(df['CAT']==cat) & (df['ID']!=iden)]['ID']) for cat, iden in zip(df['CAT'],df['ID'])]
df['New2'] = [np.random.choice(df[df['CAT']!=cat]['ID']) for cat in df['CAT']]


In [11]: df
Out[12]: 
  CAT  ID  New1  New2
0   A  87    67    76
1   A  56    67    76
2   A  67    56    36
3   D  76    36    87
4   D  36    76    67

Upvotes: 0

run-out
run-out

Reputation: 3184

I tried to find a solution using vectors but was unable. This solution iterates through the index and calculates new values for New1 and New2.

This will achieve the result I believe you are looking for.

for i in df.index:
    # Grab the category variable for each row.
    cat = df.loc[i,'Cat']

    # Set column New1
    mask1 = df['Cat'] == cat
    mask2 = df.index != i
    df.at[i,'New1']= df[mask1 & mask2]["ID"].sample().iloc[0]

    # Set column New2
    mask3 = df['Cat'] != cat
    df.at[i,'New2']= df[mask3]["ID"].sample().iloc[0]

print(df) 1st one:

 ID Cat  New1  New2
0  87   A  56.0  76.0
1  56   A  87.0  36.0
2  67   A  56.0  76.0
3  76   D  36.0  87.0
4  36   D  76.0  87.0

print(df) 2nd one:

  ID Cat  New1  New2
0  87   A  67.0  36.0
1  56   A  87.0  36.0
2  67   A  87.0  76.0
3  76   D  36.0  67.0
4  36   D  76.0  67.0

You can see from these result you are getting random results through the use of sample().

Upvotes: 1

Related Questions