Jason
Jason

Reputation: 333

Python apply function to each row of DataFrame

I have DataFrame with two columns: Type and Name. The values in each cell are lists of equal length, i.e we have pairs (Type, Name). I want to:

  1. Group Name by it's Type
  2. Create column Type with the values of Names

My current code is a for loop:

for idx, row in df.iterrows():
    for t in list(set(row["Type"])):
        df.at[idx, t] = [row["Name"][i] for i in range(len(row["Name"])) if row["Type"][i] == t]

but it works very slow. How can I speed up this code?

EDIT Here is the code example which ilustrates what I want to obtain but in a faster way:

import pandas as pd
df = pd.DataFrame({"Type": [["1", "1", "2", "3"], ["2","3"]], "Name": [["A", "B", "C", "D"], ["E", "F"]]})

unique = list(set(row["Type"]))
for t in unique:
    df[t] = None
    df[t] = df[t].astype('object')

for idx, row in df.iterrows():
    for t in unique:
        df.at[idx, t] = [row["Name"][i] for i in range(len(row["Name"])) if row["Type"][i] == t]

enter image description here

Upvotes: 0

Views: 2100

Answers (3)

SergFSM
SergFSM

Reputation: 1491

is it the result you want? (if not then add to your question an example of desired output):

res = df.explode(['Name','Type']).groupby('Type')['Name'].agg(list)

print(res)
'''
Type
1    [A, B]
2    [C, E]
3    [D, F]
Name: Name, dtype: object

UPD

df1 = df.apply(lambda x: pd.Series(x['Name'],x['Type']).groupby(level=0).agg(list).T,1)
res = pd.concat([df,df1],axis=1)

print(res)
'''
           Type          Name       1    2    3
0  [1, 1, 2, 3]  [A, B, C, D]  [A, B]  [C]  [D]
1        [2, 3]        [E, F]     NaN  [E]  [F]

Upvotes: 0

Chris Seeling
Chris Seeling

Reputation: 656

If I understand correctly your dataframe looks something like this:

df = pd.DataFrame({'Name':['a,b,c','d,e,f,g'], 'Type':['3,3,2','1,2,2,1']}) 


Name    Type
0   a,b,c   3,3,2
1   d,e,f,g 1,2,2,1

where the elements are lists of strings. Start with running:

df['Name:Type'] = (df['Name']+":"+df['Type']).map(process)

using:

def process(x):
    x_,y_ = x.split(':')
    x_ = x_.split(','); y_ = y_.split(',')
    s = zip(x_,y_)
    str_ = ','.join(':'.join(y) for y in s)
    return str_

Then you will get:

enter image description here

This reduces the problem to a single column. Finally produce the dataframe required by:

l = ','.join(df['Name:Type'].to_list()).split(',')
pd.DataFrame([i.split(':') for i in l], columns=['Name','Type'])

Giving: enter image description here

Upvotes: 0

rh-calvin
rh-calvin

Reputation: 23

You could write a function my_function(param) and then do something like this:

df['type'] = df['name'].apply(lambda x: my_function(x))

There are likely better alternatives to using lambda functions, but lambdas are what I remember. If you post a simplified mock of your original data and what the desired output should look like, it may help you find the best answer to your question. I'm not certain I understand what you're trying to do. A literal group by should be done using Dataframes' groupby method.

Upvotes: 1

Related Questions