使用Pandas过滤来自Dataframe的两列的非数字数据

时间:2016-04-06 05:15:15

标签: excel numpy pandas

我正在加载一个Pandas数据框,它有许多数据类型(从Excel加载)。两个特定的列应该是浮点数,但有时候研究人员会输入一个随机评论,例如“未测量”。我需要删除任何行,其中两列之一中的任何值不是数字,并在其他列中保留非数字数据。一个简单的用例看起来像这样(真正的表有几千行...)

class="fa fa-plus fa-2x"

这导致此数据表:

import pandas as pd

df = pd.DataFrame(dict(A = pd.Series([1,2,3,4,5]), B = pd.Series([96,33,45,'',8]), C = pd.Series([12,'Not measured',15,66,42]), D = pd.Series(['apples', 'oranges', 'peaches', 'plums', 'pears'])))

我不清楚如何到达这张桌子:

    A   B   C               D
0   1   96  12              apples
1   2   33  Not measured    oranges
2   3   45  15              peaches
3   4       66              plums
4   5   8   42              pears

我尝试过dropna,但是类型是“对象”,因为有非数字条目。 我不能在没有转换整个表的情况下将值转换为浮点数,或者在一次丢失与行中其他数据的关系时执行一个系列。也许有一些简单的我不理解?

1 个答案:

答案 0 :(得分:1)

您可以先创建包含BCapply to_numeric列的子集,检查all值是否为notnull。然后使用boolean indexing

print df[['B','C']].apply(pd.to_numeric, errors='coerce').notnull().all(axis=1)
0     True
1    False
2     True
3    False
4     True
dtype: bool

print df[df[['B','C']].apply(pd.to_numeric, errors='coerce').notnull().all(axis=1)]
   A   B   C        D
0  1  96  12   apples
2  3  45  15  peaches
4  5   8  42    pears

下一个解决方案使用str.isdigitisnull以及xor(^):

print df['B'].str.isdigit().isnull() ^ df['C'].str.isdigit().notnull()
0     True
1    False
2     True
3    False
4     True
dtype: bool

print df[df['B'].str.isdigit().isnull() ^ df['C'].str.isdigit().notnull()]
   A   B   C        D
0  1  96  12   apples
2  3  45  15  peaches
4  5   8  42    pears

to_numericisnullnotnull的解决方案最快:

print df[pd.to_numeric(df['B'], errors='coerce').notnull() 
       ^ pd.to_numeric(df['C'], errors='coerce').isnull()]

   A   B   C        D
0  1  96  12   apples
2  3  45  15  peaches
4  5   8  42    pears

<强>计时

#len(df) = 5k
df = pd.concat([df]*1000).reset_index(drop=True)

In [611]: %timeit df[pd.to_numeric(df['B'], errors='coerce').notnull() ^ pd.to_numeric(df['C'], errors='coerce').isnull()]
1000 loops, best of 3: 1.88 ms per loop

In [612]: %timeit df[df['B'].str.isdigit().isnull() ^ df['C'].str.isdigit().notnull()]
100 loops, best of 3: 16.1 ms per loop

In [613]: %timeit df[df[['B','C']].apply(pd.to_numeric, errors='coerce').notnull().all(axis=1)]
The slowest run took 4.28 times longer than the fastest. This could mean that an intermediate result is being cached 
100 loops, best of 3: 3.49 ms per loop