有没有一种有效的方法来检查列是否有混合dtypes?

cs9*_*s95 18 python numpy typechecking dataframe pandas

考虑

np.random.seed(0)
s1 = pd.Series([1, 2, 'a', 'b', [1, 2, 3]])
s2 = np.random.randn(len(s1))
s3 = np.random.choice(list('abcd'), len(s1))


df = pd.DataFrame({'A': s1, 'B': s2, 'C': s3})
df
           A         B  C
0          1  1.764052  a
1          2  0.400157  d
2          a  0.978738  c
3          b  2.240893  a
4  [1, 2, 3]  1.867558  a
Run Code Online (Sandbox Code Playgroud)

列"A"具有混合数据类型.我想提出一个非常快速的方法来确定这一点.它不会像检查是否那样简单type == object,因为那会将"C"识别为误报.

我可以想到这样做

df.applymap(type).nunique() > 1

A     True
B    False
C    False
dtype: bool
Run Code Online (Sandbox Code Playgroud)

但是调用typeatop applymap非常慢.尤其适用于较大的框架

%timeit df.applymap(type).nunique() > 1
3.95 ms ± 88 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Run Code Online (Sandbox Code Playgroud)

我们能做得更好(也许是NumPy)?如果你的论点足够令人信服,我可以接受"不".:-)

Ale*_*ley 13

在熊猫中,infer_dtype()这里可能会有所帮助.

用Cython(代码链接)编写,它返回一个字符串,总结传递对象中的值.它在熊猫的内部使用了很多,所以我们可能会合理地期望它的设计考虑了效率.

>>> from pandas.api.types import infer_dtype
Run Code Online (Sandbox Code Playgroud)

现在,A列是整数和其他一些类型的混合:

>>> infer_dtype(df.A)
'mixed-integer'
Run Code Online (Sandbox Code Playgroud)

B列的值都是浮动类型:

>>> infer_dtype(df.B)
'floating'
Run Code Online (Sandbox Code Playgroud)

C列包含字符串:

>>> infer_dtype(df.B)
'string'
Run Code Online (Sandbox Code Playgroud)

混合值的一般"catchall"类型只是"混合":

>>> infer_dtype(['a string', pd.Timedelta(10)])
'mixed'
Run Code Online (Sandbox Code Playgroud)

浮点数和整数的混合是''mixed-integer-float'':

>>> infer_dtype([3.141, 99])
'mixed-integer-float'
Run Code Online (Sandbox Code Playgroud)

要创建您在问题中描述的功能,一种方法可能是创建一个捕获相关混合情况的函数:

def is_mixed(col):
    return infer_dtype(col) in ['mixed', 'mixed-integer']
Run Code Online (Sandbox Code Playgroud)

然后你有:

>>> df.apply(is_mixed)
A     True
B    False
C    False
dtype: bool
Run Code Online (Sandbox Code Playgroud)


Pau*_*zer 5

这是一种使用Python3中不能比较不同类型的事实的方法.我的想法是max在阵列上运行,内置应该相当快.它确实是短暂的.

def ismixed(a):
    try:
        max(a)
        return False
    except TypeError as e: # we take this to imply mixed type
        msg, fst, and_, snd = str(e).rsplit(' ', 3)
        assert msg=="'>' not supported between instances of"
        assert and_=="and"
        assert fst!=snd
        return True
    except ValueError as e: # catch empty arrays
        assert str(e)=="max() arg is an empty sequence"
        return False
Run Code Online (Sandbox Code Playgroud)

但它不会捕获混合数字类型.此外,不支持比较的对象可能会使其绊倒.

但它的速度相当快.如果我们剥离所有pandas开销:

v = df.values

list(map(is_mixed, v.T))
# [True, False, False]
timeit(lambda: list(map(ismixed, v.T)), number=1000)
# 0.008936170022934675
Run Code Online (Sandbox Code Playgroud)

为了比较

timeit(lambda: list(map(infer_dtype, v.T)), number=1000)
# 0.02499613002873957
Run Code Online (Sandbox Code Playgroud)