代码之家  ›  专栏  ›  技术社区  ›  Spinor8

比较numpy/pandas数组与混合元素(字符串和浮点数)

  •  3
  • Spinor8  · 技术社区  · 6 年前

    我有一些numpy数组(或者与pandas数据帧相当的数据帧,因为它可以很容易地转换为)希望进行比较。这些数组/数据帧同时包含数字和字符串。

    对于纯粹的数字,我可以做以下的事情。

    import numpy as np
    a = np.array([[1.0, 2.0], [1.00001, 2.00001]])
    b = np.array([[1.000001, 2.00001], [1.00001, 2.00001]])
    print(np.allclose(a, b, 1e-9))
    # output: False
    print(np.allclose(a, b, 1e-4))
    # output: True
    

    c = np.array([[1.0, "Cat"], [1.00001, 2.00001]])
    d = np.array([[1.000001, "Dog"], [1.00001, 2.00001]])
    e = np.array([[1.000001, "Cat"], [1.00001, 2.00001]])
    print(np.allclose(c, d, 1e-4))
    # expected output: False on account of the string difference
    print(np.allclose(c, e, 1e-4))
    # expected output: True
    

    我尝试将其转换成熊猫数据帧,希望内置测试模块可以做到这一点。

    import pandas as pd
    from pandas.util import testing as pdtest
    df_c = pd.DataFrame(c)
    df_d = pd.DataFrame(d)
    df_e = pd.DataFrame(e)
    print(pdtest.assert_almost_equal(df_c, df_e, check_exact=False, check_less_precise=4))
    # expected output: True as the strings match and numbers agree within tolerance.
    

    但这不管用。有没有一种方法可以比较数组,其中数值元素与指定的公差进行比较,而字符串元素则进行精确比较?

    编辑:公差仅适用于浮动元素。对于字符串,需要完全匹配。

    1 回复  |  直到 6 年前
        1
  •  1
  •   hpaulj    6 年前
    def myequal(i,j):
        # scalar comparison function of your own design
        if isinstance(i,str):
            return i==j
        else:
            return 1e04>abs(i-j)
    

    作为对象数据类型的示例数组:

    In [74]: c = np.array([[1.0, "Cat"], [1.00001, 2.00001]],object)
        ...: d = np.array([[1.000001, "Dog"], [1.00001, 2.00001]],object)
        ...: e = np.array([[1.000001, "Cat"], [1.00001, 2.00001]],object)
    
    In [75]: c
    Out[75]: 
    array([[1.0, 'Cat'],
           [1.00001, 2.00001]], dtype=object)
    In [76]: d
    Out[76]: 
    array([[1.000001, 'Dog'],
           [1.00001, 2.00001]], dtype=object)
    In [77]: e
    Out[77]: 
    array([[1.000001, 'Cat'],
           [1.00001, 2.00001]], dtype=object)
    

    使用 frompyfunc 应用 myequal 到数组的元素。基本上它负责广播迭代

    In [78]: f = np.frompyfunc(myequal,2,1)
    In [79]: f(c,d)
    Out[79]: 
    array([[True, False],
           [True, True]], dtype=object)
    In [80]: f(c,e)
    Out[80]: 
    array([[True, True],
           [True, True]], dtype=object)
    

    没有 object DTYPE,您的数组是字符串DTYPE,唯一常见的DTYPE:

    In [81]: np.array([[1.0, "Cat"], [1.00001, 2.00001]])
    Out[81]: 
    array([['1.0', 'Cat'],
           ['1.00001', '2.00001']], dtype='<U32')
    

    这会导致 allclose/isclose 因为无法测试字符串 np.inf :

    In [82]: np.isclose(_,_)
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-82-c2e4de5fe672> in <module>()
    ----> 1 np.isclose(_,_)
    
    /usr/local/lib/python3.6/dist-packages/numpy/core/numeric.py in isclose(a, b, rtol, atol, equal_nan)
       2330     y = array(y, dtype=dt, copy=False, subok=True)
       2331 
    -> 2332     xfin = isfinite(x)
       2333     yfin = isfinite(y)
       2334     if all(xfin) and all(yfin):
    
    TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
    

    np.isfinite 适用于数值数组,而不是字符串数组。