title: Sorting by 3 columns and assigning column attribute based on match in pandas
body: <p>I'm currently trying to sort a dataframe with 9 columns, but only on values within 3 of the columns, and its proving more difficult than I thought. </p>
  
  <p>Basically I'm trying to mark: </p>
  
  <ul>
  <li>1) If the three columns match across all three columns mark as "Full Match"  </li>
  <li>2) If they match across two of the columns but the last one has a different value mark as "Conflicting Value" or "Partial Match" if the value is NA </li>
  <li>3) If there is only one value and the rest are NA mark as "Unique" </li>
  <li>4) If all three columns are NA mark as "Empty"</li>
  </ul>
  
  <p>Initially before I ran into this problem, I used <code>df = df.sort_values(by = ['Cage_name_match_eid', 'Facility_match_eid', 'Clean_name_match_eid'], ascending = False)</code></p>
  
  <p>However, that didn't provide any correlation by which ones matched across a different column. My next attempt used <code>df[df.duplicated(['Cage_name_match_eid', 'Facility_match_eid', 'Clean_name_match_eid'], keep=False)]</code> this removed all unique values, to which I still need.</p>
  
  <p>Finally I wrote the most unpythonic, inelegant function to sort based on truth values. Its working to some degree, however it is marking unique values as conflicting values, I figured I'd ask here before I write a sorting algorithm that CS teachers will use as an example of what <strong>NOT</strong> to do when sorting. </p>
  
  <p>Here is the function:</p>
  
  <pre><code>def dupe_finder(row):
      if ((row['Cage_name_match_eid']) and (row['Facility_match_eid']) and (row['Clean_name_match_eid'])) is not None:
  
          if (row['Cage_name_match_eid'] == row['Facility_match_eid']) and \
                  (row['Facility_match_eid'] == row['Clean_name_match_eid']) and \
                  (row['Cage_name_match_eid'] == row['Clean_name_match_eid']):
              val = 'Full Match'
              return val
          elif (row['Cage_name_match_eid'] == row['Facility_match_eid']) or \
                  (row['Facility_match_eid'] == row['Clean_name_match_eid']) or \
                  (row['Cage_name_match_eid'] == row['Clean_name_match_eid']):
              val = 'Partial Match'
              return val
          elif (row['Cage_name_match_eid'] != row['Facility_match_eid']) or \
                  (row['Facility_match_eid'] != row['Clean_name_match_eid']) or \
                  (row['Cage_name_match_eid'] != row['Clean_name_match_eid']):
              val = 'Conflicting Values'
              return val
          elif (row['Cage_name_match_eid'] != row['Facility_match_eid']) and \
                  (row['Facility_match_eid'] != row['Clean_name_match_eid']) and \
                  (row['Cage_name_match_eid'] != row['Clean_name_match_eid']):
              val = 'Unique'
              return val
      else:
          val = 'Empty'
          return val
  
  
  df['Dupes'] = left_over.apply(dupe_finder, axis = 1)
  </code></pre>
  
  <p>And here is some sample data:</p>
  
  <pre><code>    Cage_name_match_eid Facility_match_eid Clean_name_match_eid          Dupes
  122                 RrDyv0            RrDyv0              RrDyv0    Full Match
  529                 JKvKeF            JKvKeF              JKvKeF    Full Match
  133                 NaN               JR_enw              JR_enw  Partial Match
  297                 NaN               CfODTf              CfODTf  Partial Match
  465                 NaN               KeJuQu              KeJuQu  Partial Match
  20                  NaN               J8dWGK              J8dWGK  Partial Match
  626                 NaN               Et8z8K              Et8z8K  Partial Match
  448                 NaN               Q2mmII              Q2mmII  Partial Match
  226                 NaN               Fi1goI              Fi1goI  Partial Match
  93                  GqSMp             qGMsp               qGMsp   Conflicting Match
  60                  Jua2hK            Jb7fQF              Jb7fQF  Conflicting Match
  558                 NaN               KE_nxZ              KE_nxZ  Partial Match
  300                 NaN               Ohqbid              Ohqbid  Partial Match
  84                  NaN               KfcqtH              KfcqtH  Partial Match
  461                 NaN               NaN                 NaN      Empty
  </code></pre>