merging varying number of rows and columns by multiple conditions in python

Viewed 327

updated Problem: Why does it not merge a_date, a_par, a_cons, a_ment and a_le. These are appended as columns without values but in the original dataset they have values.

Here is how the dataset looks like

         connector   type   q_text   a_text   var1   var2 
   1        1111      1      aa       None    xx     ps
   2        9999      2      None     tt      jjjj   pppp
   3        1111      2      None     uu      None   oo
   4        9999      1      bb       None    yy     Rt
   5        9999      1      cc       None    zz     tR

Goal: how the dataset should look like

         connector   q_text   a_text    var1   var1.1   var2   var2.1
   1        1111      aa        uu       xx     None     ps      oo
   2        9999      bb        tt       yy     jjjj     Rt      pppp
   3        9999      cc        tt       zz     jjjj     tR      pppp

Logic: Column type has either value 1 or 2 with multiple rows having value 1 but only one row (with the same value in connector) has value 2

Here are the main merging rules:

  1. Merge every row of type=1 with its corresponding (connector) type=2 row.

  2. Since multiple rows of type=1 have the same connector value, I don't want to merge solely one row of type=1 but all of them, each with the sole type==2 row.

  3. Since some columns (e.g. a_text) follow left-join logic, values can be overridden without adding an extra column.

  4. Since var2 values cannot be merged by left-join because they are non-exclusionary with regard to the rows connector value, i want to have extra columns (var1.1, var2.1) for those values (pppp, jjjj).

In summary (and having in mind that i only speak of rows that have the same connector values): If q_text is None i first, want to replace the values in a_text with the a_text value (see above table tt and uu) of the corresponding row (same connector value) and secondly, want to append some other values (var1 and var2) of the very same corresponding row as new columns. Also, there are rows with a unique connector value that is not going to be matched. I want to keep those rows though.

I only want to "drop" the type=2 rows that get merged with their corresponding type=1 row**(s)**. In other words: I dont want to keep the rows of type=2 that have a match and get merged into their corresponding (connector) type=1 rows. I want to keep all other rows though.

Solution by @victor__von__doom here merging varying number of rows by multiple conditions in python was answered when i originally wanted to keep all of the "type"=2 columns(values).

Code i used: merged Perso, q_text and a_text

df.loc[df['type'] == 2, 'a_date'] = df['q_date']
df.loc[df['type'] == 2, 'a_par'] = df['par']
df.loc[df['type'] == 2, 'a_cons'] = df['cons']
df.loc[df['type'] == 2, 'a_ment'] = df['pret']
df.loc[df['type'] == 2, 'a_le'] = df['q_le']
my_cols = ['Perso', 'q_text','a_text', 'a_le', 'q_le', 'q_date', 'par', 'cons', 'pret', 'q_le', 'a_date','a_par', 'a_cons', 'a_ment', 'a_le']
df[my_cols] = df.sort_values(['connector','type']).groupby('connector')[my_cols].transform(lambda x: x.bfill())
df.dropna(subset=['a_text', 'Perso'],inplace=True)
df.reset_index(drop=True,inplace=True)

Data: This is a representation of the core dataset. Unfortunately i cannot share the actual data due to privacy laws.

Perso ID per q_le a_le pret par form q_date name IO_ID part area q_text a_text country cons dig connector type
J Ws 1-1/4/2001-11-12/1 1999-2009 None 4325 'Mi, h', 'd' Cew Thre 2001-11-12 None 345 rede s — H None wr ede Terd e e r 2001-11-12.1.g9 999999999 2
S ts 9-3/6/2003-10-14/1 1994-2004 None 23 'sd, h' d-g Thre 2003-10-14 None 34555 The l? I None Tre Thr ede re 2001-04-16.1.a9 333333333 2
On d 6-1/6/2005-09-03/1 1992-2006 None 434 'uu h' d-g Thre 2005-09-03 None 7313 Thde l? I None T e Th rede dre 2001-08-07.1.e4 111111111 2
None 3-4/4/2000-07-07/1 1992-2006 1223 None 'uu h' dfs Thre 2000-07-07 Th r 7413 Thde Tddde Thd de None Thre de 2001-07-06.1.j3 111111111 1
None 2-1/6/2001-11-12/1 1999-2009 1444 None 'Mi, h', 'd' d-g Thre 2001-11-12 T rj 7431 Thde l? I Th dde None Thr ede 2001-11-12.1.s7 999999999 1
None 1-6/4/2007-11-01/1 1993-2010 2353 None None d-g Thre 2007-11-01 Thrj 444 Thed l. I Tgg gg None Thre de we e 2001-06-11.1.g9 654982984 1
1 Answers

EDIT v2 with additional columns

This version ensures the values in the additional columns are not impacted.

c = ['connector','type','q_text','a_text','var1','var2','cumsum','country','others']
d = [[1111, 1, 'aa',  None, 'xx',   'ps',   0, 'US', 'other values'],
     [9999, 2, None,  'tt', 'jjjj', 'pppp', 0, 'UK', 'no values'],
     [1111, 2, None,  'uu', None,   'oo',   1, 'US', 'some values'],
     [9999, 1, 'bb',  None, 'yy',   'Rt',   1, 'UK', 'more values'],
     [9999, 1, 'cc',  None, 'zz',   'tR',   2, 'UK', 'less values']]

import pandas as pd
pd.set_option('display.max_columns', None)
df = pd.DataFrame(d,columns=c)

print (df)

df.loc[df['type'] == 2, 'var1.1'] = df['var1']
df.loc[df['type'] == 2, 'var2.1'] = df['var2']

my_cols = ['q_text','a_text','var1','var2','var1.1','var2.1']

df[my_cols] = df.sort_values(['connector','type']).groupby('connector')[my_cols].transform(lambda x: x.bfill())

df.dropna(subset=['q_text'],inplace=True)
df.reset_index(drop=True,inplace=True)

print (df)

Original DataFrame:

   connector  type q_text a_text  var1  var2  cumsum country        others
0       1111     1     aa   None    xx    ps       0      US  other values
1       9999     2   None     tt  jjjj  pppp       0      UK     no values
2       1111     2   None     uu  None    oo       1      US   some values
3       9999     1     bb   None    yy    Rt       1      UK   more values
4       9999     1     cc   None    zz    tR       2      UK   less values

Updated DataFrame

   connector  type q_text a_text var1 var2  cumsum country        others  var1.1 var2.1
0       1111     1     aa     uu   xx   ps       0      US  other values    None     oo 
1       9999     1     bb     tt   yy   Rt       1      UK   more values    jjjj   pppp 
2       9999     1     cc     tt   zz   tR       2      UK   less values    jjjj   pppp 
Related