nodes: 0, module; 1, function_definition; 2, function_name:assortativity_attributes; 3, parameters; 4, block; 5, identifier:user; 6, expression_statement; 7, expression_statement; 8, expression_statement; 9, expression_statement; 10, for_statement; 11, expression_statement; 12, for_statement; 13, return_statement; 14, comment:"""
      Computes the assortativity of the nominal attributes.
  
      This indicator measures the homophily of the current user with his
      correspondants, for each attributes. It returns a value between 0
      (no assortativity) and 1 (all the contacts share the same value):
      the percentage of contacts sharing the same value.
      """; 15, assignment; 16, assignment; 17, assignment; 18, pattern_list; 19, call; 20, block; 21, assignment; 22, identifier:a; 23, attribute; 24, block; 25, identifier:assortativity; 26, identifier:matrix; 27, call; 28, identifier:neighbors; 29, list_comprehension; 30, identifier:neighbors_attrbs; 31, dictionary; 32, identifier:i; 33, identifier:u_name; 34, identifier:enumerate; 35, argument_list; 36, expression_statement; 37, if_statement; 38, if_statement; 39, identifier:assortativity; 40, dictionary; 41, identifier:user; 42, identifier:attributes; 43, expression_statement; 44, expression_statement; 45, expression_statement; 46, identifier:matrix_undirected_unweighted; 47, argument_list; 48, identifier:k; 49, for_in_clause; 50, if_clause; 51, call; 52, assignment; 53, boolean_operator; 54, block; 55, attribute; 56, block; 57, assignment; 58, assignment; 59, assignment; 60, identifier:user; 61, identifier:k; 62, call; 63, comparison_operator:k != user.name; 64, identifier:matrix_index; 65, argument_list; 66, identifier:correspondent; 67, call; 68, boolean_operator; 69, comparison_operator:matrix[0][i] == 0; 70, continue_statement; 71, identifier:correspondent; 72, identifier:has_attributes; 73, expression_statement; 74, identifier:total; 75, call; 76, identifier:den; 77, call; 78, subscript; 79, conditional_expression:total / den if den != 0 else None; 80, attribute; 81, argument_list; 82, identifier:k; 83, attribute; 84, identifier:user; 85, attribute; 86, argument_list; 87, comparison_operator:correspondent is None; 88, comparison_operator:u_name == user.name; 89, subscript; 90, integer:0; 91, assignment; 92, identifier:sum; 93, generator_expression; 94, identifier:sum; 95, generator_expression; 96, identifier:assortativity; 97, identifier:a; 98, binary_operator:total / den; 99, comparison_operator:den != 0; 100, None; 101, attribute; 102, identifier:keys; 103, identifier:user; 104, identifier:name; 105, attribute; 106, identifier:get; 107, identifier:u_name; 108, None; 109, identifier:correspondent; 110, None; 111, identifier:u_name; 112, attribute; 113, subscript; 114, identifier:i; 115, subscript; 116, attribute; 117, integer:1; 118, for_in_clause; 119, if_clause; 120, integer:1; 121, for_in_clause; 122, if_clause; 123, identifier:total; 124, identifier:den; 125, identifier:den; 126, integer:0; 127, identifier:user; 128, identifier:network; 129, identifier:user; 130, identifier:network; 131, identifier:user; 132, identifier:name; 133, identifier:matrix; 134, integer:0; 135, identifier:neighbors_attrbs; 136, attribute; 137, identifier:correspondent; 138, identifier:attributes; 139, identifier:n; 140, identifier:neighbors; 141, boolean_operator; 142, identifier:n; 143, identifier:neighbors; 144, comparison_operator:n in neighbors_attrbs; 145, identifier:correspondent; 146, identifier:name; 147, comparison_operator:n in neighbors_attrbs; 148, comparison_operator:user.attributes[a] == neighbors_attrbs[n][a]; 149, identifier:n; 150, identifier:neighbors_attrbs; 151, identifier:n; 152, identifier:neighbors_attrbs; 153, subscript; 154, subscript; 155, attribute; 156, identifier:a; 157, subscript; 158, identifier:a; 159, identifier:user; 160, identifier:attributes; 161, identifier:neighbors_attrbs; 162, identifier:n
code: def assortativity_attributes(user):
      """
      Computes the assortativity of the nominal attributes.
  
      This indicator measures the homophily of the current user with his
      correspondants, for each attributes. It returns a value between 0
      (no assortativity) and 1 (all the contacts share the same value):
      the percentage of contacts sharing the same value.
      """
  
      matrix = matrix_undirected_unweighted(user)
  
      neighbors = [k for k in user.network.keys() if k != user.name]
      neighbors_attrbs = {}
      for i, u_name in enumerate(matrix_index(user)):
          correspondent = user.network.get(u_name, None)
          if correspondent is None or u_name == user.name or matrix[0][i] == 0:
              continue
  
          if correspondent.has_attributes:
              neighbors_attrbs[correspondent.name] = correspondent.attributes
  
      assortativity = {}
      for a in user.attributes:
          total = sum(1 for n in neighbors if n in neighbors_attrbs and user.attributes[a] == neighbors_attrbs[n][a])
          den = sum(1 for n in neighbors if n in neighbors_attrbs)
          assortativity[a] = total / den if den != 0 else None
  
      return assortativity