Python Pandas - 基于值删除行

4
我有一个 Pandas 数据框,其中包含 A 和 B 两列。
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(0,100,size=(10, 2)), columns=list('AB'))

我创建了 C 列,如果 A > B,则该列为空。
df['C'] = np.select([ df.A > df.B ], [df.A], default=np.NaN)

这意味着:

    A   B     C
0  95  19  95.0
1  46  11  46.0
2  96  86  96.0
3  22  61   NaN
4  69   1  69.0
5  78  91   NaN
6  42   7  42.0
7  24  28   NaN
8  55  92   NaN
9  92  16  92.0

我会使用多种方法删除df.C值为NaN的行:

df = df.dropna(subset=['C'], how='any')

或者
df = df.drop(df[pd.isnull(df.C)].index)

或者
df = df.drop(df[(pd.isnull(df.C))].index)

这三种方法都给我大概相同的行数。在这种情况下:

    A   B     C
0  95  19  95.0
1  46  11  46.0
2  96  86  96.0
4  69   1  69.0
6  42   7  42.0
9  92  16  92.0

但是当我不使用数字,例如一个字符串:

df['C'] = np.select([ df.A > df.B ], ['yes'], default=np.NaN)

然后,同样的3种方法删除df.C为NaN的行不会被过滤。例如,当df.A> df.B将列C设置为yes时,我得到了如下结果:

    A   B    C
0   6  70  nan
1  85  46  yes
2  76  87  nan
3  77  36  yes
4  73  18  yes
5   1  41  nan
6  19  69  nan
7  62  89  nan
8   6   7  nan
9  35  75  nan

我可以通过将pd.NaN替换为类似于“IGNORE”的字符串,然后过滤“IGNORE”来解决这个问题,但我发现这个结果在其他方面是出乎意料的。
df['C'] = np.select([ df.A > df.B ], ['yes'], default='IGNORE')
df = df.drop(df[(df.C == 'IGNORE')].index)

这里发生了什么?(当 df.C 是一个字符串时,我的 pd.NaN 是否被转换为字符串?)


我正在使用64位Python 2.7.13、Pandas 0.19.2和Numpy 1.11.3在Windows 10上。


@Psidom 是的,没错。它似乎是指"不是一个数字",并被转换为字符串"nan"。 - philshem
@Psidom 如果您将您的评论写成答案,我很乐意接受它。虽然它并没有真正解释原因,但肯定解决了问题。 - philshem
2个回答

3

避免数据溢出,仅取有限的数值。

df = df[np.isfinite(df['C'])]

编辑:

根据您的评论,nanstring类型,因此,基于数值删除行:

df = df[df.C != "nan"] 将起作用

df[df.C.notnull()]
    A   B    C
0  67  23  yes
1  91  61  yes
2  30  92  nan
3  53  97  nan
4  81  11  yes
5  23   7  yes
6  47  39  yes
7  11  27  nan
8  46  55  nan
9  31  82  nan
df = df[df.C != "nan"]


    A   B    C
0  67  23  yes
1  91  61  yes
4  81  11  yes
5  23   7  yes
6  47  39  yes 

我遇到了一个 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'' - philshem
我尝试模拟了一下你的问题,并得出了这个解决方案。 import numpy as np import pandas as pddf = pd.DataFrame(np.random.randint(0,100,size=(10, 2)), columns=list('AB'))df['C'] = np.select([ df.A > df.B ], [df.A], default=np.NaN)print dfA B C0 81 17 81.0 1 14 67 NaN 2 16 9 16.0 3 25 31 NaN 4 35 36 NaN 5 56 5 56.0 6 18 20 NaN 7 32 4 32.0 8 46 51 NaN 9 53 34 53.0df = df[np.isfinite(df['C'])]print dfA B C0 81 17 81.0 2 16 9 16.0 5 56 5 56.0 7 32 4 32.0 9 53 34 53.0 - MANOJ REDDY
好的,区别在于我的实际代码(而不是我在这里发布的示例代码),请尝试这样做:df['C'] = np.select([ df.A > df.B ], [u'yes'], default=np.NaN) - philshem

1
你的情况类似于这个:
np.array([1,2,'3',np.nan])
# array(['1', '2', '3', 'nan'], 
#       dtype='<U21')

由于np.select也返回一个数组,如果你进一步检查

type(np.nan)
# float

str(np.nan)
# 'nan'

因此,np.nan 是一个浮点数,但是 numpy 数组更喜欢单一的数据类型,除了结构化数组之外。所以当数组中有字符串元素时,所有元素都会被转换为字符串。


对于您的情况,如果您有字符串列,可以使用None代替np.nan作为默认值,这将创建一个缺失值,可以通过isnull()检查并与dropna()一起使用:
import pandas as pd
import numpy as np
​
df = pd.DataFrame(np.random.randint(0,100,size=(10, 2)), columns=list('AB'))
df['C'] = np.select([ df.A > df.B ], ['yes'], default=None)

df.dropna()

#    A  B     C
#0  82  1   yes
#3  84  8   yes
#6  52  30  yes
#7  68  61  yes
#9  91  87  yes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接