How to iterate over dfs and append data with combine names

Viewed 190

i have this problem to solve, this is a continuation of a previus question How to iterate over pandas df with a def function variable function and the given answer worked perfectly, but now i have to append all the data in a 2 columns dataframe (Adduct_name and mass).

This is from the previous question:

My goal: i have to calculate the "adducts" for a given "Compound", both represents numbes, but for eah "Compound" there are 46 different "Adducts".

Each adduct is calculated as follow:

Adduct 1 = [Exact_mass*M/Charge + Adduct_mass]

where exact_mass = number, M and Charge = number (1, 2, 3, etc) according to each type of adduct, Adduct_mass = number (positive or negative) according to each adduct.

My data: 2 data frames. One with the Adducts names, M, Charge, Adduct_mass. The other one correspond to the Compound_name and Exact_mass of the Compounds i want to iterate over (i just put a small data set)

Adducts: df_al

import pandas as pd 
data = [["M+3H", 3, 1, 1.007276], ["M+3Na", 3, 1, 22.989], ["M+H", 1, 1, 
1.007276], ["2M+H", 1, 2, 1.007276], ["M-3H", 3, 1, -1.007276]]
df_al = pd.DataFrame(data, columns=["Ion_name", "Charge", "M", "Adduct_mass"])

Compounds: df

import pandas as pd 
data1 = [[1, "C3H64O7", 596.465179], [2, "C30H42O7", 514.293038], [4, 
"C44H56O8", 712.397498], [4, "C24H32O6S", 448.191949], [5, "C20H28O3", 
316.203834]]
df = pd.DataFrame(data1, columns=["CdId", "Formula", "exact_mass"])

The solution to this problem was:

df_name = df_al["Ion_name"]
df_mass = df_al["Adduct_mass"]
df_div = df_al["Charge"]
df_M = df_al["M"]
#Defining general function 
def Adduct(x,i):
    return x*df_M[i]/df_div[i] + df_mass[i]

#Applying general function in a range from 0 to 5. 
for i in range(5):
    df[df_name.loc[i]] = df['exact_mass'].map(lambda x: Adduct(x,i))

Output

    Name exact_mass  M+3H       M+3Na        M+H        2M+H        M-3H
0   a   596.465179  199.829002  221.810726  597.472455  1193.937634 197.814450
1   b   514.293038  172.438289  194.420013  515.300314  1029.593352 170.423737
2   c   712.397498  238.473109  260.454833  713.404774  1425.802272 236.458557
3   d   448.191949  150.404592  172.386316  449.199225  897.391174  148.390040
4   e   316.203834  106.408554  128.390278  317.211110  633.414944  104.39400

Now that is the rigth calculations but i need now a file where: -only exists 2 columns (Name and mass) -All the different adducts are appended one after another

desired out put

 Name     Mass 
 a_M+3H  199.82902
 a_M+3Na 221.810726
 a_M+H   597.472455
 a_2M+H  1193.937634
 a_M-3H  197.814450 
 b_M+3H  514.293038
 .
 . 
 .
 c_M+3H

and so on.

Also i need to combine the name of the respective compound with the ion form (M+3H, M+H, etc).

At this point i have no code for that.

I would apprecitate any advice and a better approach since the begining.


This part is an update of the question above:

Is posible to obtain and ouput like this one:

  Name     Mass       RT
 a_M+3H  199.82902     1
 a_M+3Na 221.810726    1
 a_M+H   597.472455    1
 a_2M+H  1193.937634   1
 a_M-3H  197.814450    1
 b_M+3H  514.293038    3
 .           
 . 
 .
 c_M+3H                2

The RT is the same value for all forms of a compound, in this example is RT for a =1, b = 3, c =2, etc.

Is posible to incorporate (Keep this column) from the data set df (which i update here below)?. As you can see that df has more columns like "Formula" and "RT" which desapear after calculations.

import pandas as pd 
data1 = [[a, "C3H64O7", 596.465179, 1], [b, "C30H42O7", 514.293038, 3], [c, 
"C44H56O8", 712.397498, 2], [d, "C24H32O6S", 448.191949, 4], [e, "C20H28O3", 
316.203834, 1.5]]
df = pd.DataFrame(data1, columns=["Name", "Formula", "exact_mass", "RT"])  

Part three! (sorry and thank you)

this is a trial i did on a small data set (df) using the code below, with the same df_al of above.

df= enter image description here

Code

#Defining variables for calculation

df_name = df_al["Ion_name"]
df_mass = df_al["Adduct_mass"]
df_div = df_al["Charge"]
df_M = df_al["M"]
df_ID= df["Name"]

#Defining the RT dictionary

RT = dict(zip(df["Name"], df["RT"]))

#Removing RT column

df=df.drop(columns=["RT"])

#Defining general function 

def Adduct(x,i):
    return x*df_M[i]/df_div[i] + df_mass[i]

#Applying general function in a range from 0 to 46. 

for i in range(47):
    df[df_name.loc[i]] = df['exact_mass'].map(lambda x: Adduct(x,i)) 

df 

output

enter image description here

#Melting

df = pd.melt(df, id_vars=['Name'], var_name = "Adduct", value_name= "Exact_mass", value_vars=[x for x in df.columns if 'Name' not in x and 'exact' not in x])

df['name'] = df.apply(lambda x:x[0] + "_" + x[1], axis=1)

df['RT'] = df.Name.apply(lambda x: RT[x[0]] if x[0] in RT else np.nan)

del df['Name']

del df['Adduct']

df['RT'] = df.name.apply(lambda x: RT[x[0]] if x[0] in RT else np.nan)

df

output

enter image description here

Why NaN?

1 Answers

Here is how I will go about it, pandas.melt comes to rescue:

import pandas as pd
import numpy as np

from io import StringIO

s = StringIO('''
    Name exact_mass  M+3H       M+3Na        M+H        2M+H        M-3H
0   a   596.465179  199.829002  221.810726  597.472455  1193.937634 197.814450
1   b   514.293038  172.438289  194.420013  515.300314  1029.593352 170.423737
2   c   712.397498  238.473109  260.454833  713.404774  1425.802272 236.458557
3   d   448.191949  150.404592  172.386316  449.199225  897.391174  148.390040
4   e   316.203834  106.408554  128.390278  317.211110  633.414944  104.39400
''')

df = pd.read_csv(s, sep="\s+")

df = pd.melt(df, id_vars=['Name'], value_vars=[x for x in df.columns if 'Name' not in x and 'exact' not in x])



df['name'] = df.apply(lambda x:x[0] + "_" + x[1], axis=1)

del df['Name']
del df['variable']


RT = {'a':1, 'b':2, 'c':3, 'd':5, 'e':1.5}

df['RT'] = df.name.apply(lambda x: RT[x[0]] if x[0] in RT else np.nan)
df

Here is the output:

enter image description here

Related