def get_array_differences(first_array, second_array, exact=True, rtol=<NUM_LIT>, atol=<NUM_LIT>, equal_nan=True):
def compare_arrays(actual, desired, exact, rtol, atol, equal_nan):<EOL><INDENT>compare_str = '<STR_LIT>'<EOL>if actual.dtype != desired.dtype:<EOL><INDENT>compare_str += '<STR_LIT>' % (str(actual.dtype), str(desired.dtype))<EOL><DEDENT>if actual.shape != desired.shape:<EOL><INDENT>compare_str += '<STR_LIT>' % (str(actual.shape), str(desired.shape))<EOL><DEDENT>if np.nansum(actual) != np.nansum(desired):<EOL><INDENT>compare_str += '<STR_LIT>' % (str(np.nansum(actual)), str(np.nansum(desired)))<EOL><DEDENT>if exact:<EOL><INDENT>try:<EOL><INDENT>np.testing.assert_equal(actual=actual, desired=desired)<EOL><DEDENT>except AssertionError as e:<EOL><INDENT>compare_str += str(e) + "<STR_LIT:\n>"<EOL><DEDENT><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>np.testing.assert_allclose(actual=actual, desired=desired, rtol=rtol, atol=atol, equal_nan=equal_nan)<EOL><DEDENT>except AssertionError as e:<EOL><INDENT>compare_str += str(e) + "<STR_LIT:\n>"<EOL><DEDENT><DEDENT>if compare_str:<EOL><INDENT>compare_str = ("<STR_LIT>" % ("<STR_LIT>" if exact else "<STR_LIT>")) + compare_str<EOL><DEDENT>else:<EOL><INDENT>compare_str = "<STR_LIT>" % ("<STR_LIT>" if exact else "<STR_LIT>")<EOL><DEDENT>return compare_str<EOL><DEDENT>if (first_array.dtype.names is None and second_array.dtype.names is not None) or (first_array.dtype.names is not None and second_array.dtype.names is None):<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>if first_array.dtype.names is None:  <EOL><INDENT>return compare_arrays(actual=first_array, desired=second_array, exact=exact, rtol=rtol, atol=atol, equal_nan=equal_nan)<EOL><DEDENT>else:<EOL><INDENT>return_str = '<STR_LIT>'<EOL>first_array_column_names = first_array.dtype.names<EOL>second_array_column_names = second_array.dtype.names<EOL>additional_first_array_column_names = set(first_array_column_names) - set(second_array_column_names)<EOL>additional_second_array_column_names = set(second_array_column_names) - set(first_array_column_names)<EOL>if additional_first_array_column_names:<EOL><INDENT>return_str += '<STR_LIT>' % '<STR_LIT:U+002CU+0020>'.join(additional_first_array_column_names)<EOL><DEDENT>if additional_second_array_column_names:<EOL><INDENT>return_str += '<STR_LIT>' % '<STR_LIT:U+002CU+0020>'.join(additional_second_array_column_names)<EOL><DEDENT>if not additional_first_array_column_names and not additional_second_array_column_names and first_array_column_names != second_array_column_names:<EOL><INDENT>return_str += '<STR_LIT>' % (first_array_column_names, second_array_column_names)<EOL><DEDENT>common_columns = set(first_array_column_names) & set(second_array_column_names)<EOL>for column_name in common_columns:  <EOL><INDENT>first_column_data = first_array[column_name]<EOL>second_column_data = second_array[column_name]<EOL>col_compare_str = compare_arrays(actual=first_column_data, desired=second_column_data, exact=exact, rtol=rtol, atol=atol, equal_nan=equal_nan)<EOL>return_str += "<STR_LIT>" % (column_name, col_compare_str)<EOL><DEDENT>return return_str<EOL><DEDENT>
Takes two numpy.ndarrays and compares them on a column basis.
    Different column data types, missing columns and columns with different values are returned in a string.

    Parameters
    ----------
    first_array : numpy.ndarray
    second_array : numpy.ndarray

    Returns
    -------
    string