使用pandas.DataFrame中的复杂条件进行选择

Gil*_*tes 204 python pandas

例如,我有简单的DF:

import pandas as pd
from random import randint

df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9)*10 for x in xrange(10)],
                   'C': [randint(1, 9)*100 for x in xrange(10)]})
Run Code Online (Sandbox Code Playgroud)

我可以使用Pandas的方法和习语从"A"中选择"B"的相应值大于50,"C" - 不等于900的值吗?

DSM*_*DSM 344

当然!建立:

>>> import pandas as pd
>>> from random import randint
>>> df = pd.DataFrame({'A': [randint(1, 9) for x in range(10)],
                   'B': [randint(1, 9)*10 for x in range(10)],
                   'C': [randint(1, 9)*100 for x in range(10)]})
>>> df
   A   B    C
0  9  40  300
1  9  70  700
2  5  70  900
3  8  80  900
4  7  50  200
5  9  30  900
6  2  80  700
7  2  80  400
8  5  80  300
9  7  70  800
Run Code Online (Sandbox Code Playgroud)

我们可以应用列操作并获取布尔系列对象:

>>> df["B"] > 50
0    False
1     True
2     True
3     True
4    False
5    False
6     True
7     True
8     True
9     True
Name: B
>>> (df["B"] > 50) & (df["C"] == 900)
0    False
1    False
2     True
3     True
4    False
5    False
6    False
7    False
8    False
9    False
Run Code Online (Sandbox Code Playgroud)

[更新,切换到新式.loc]:

然后我们可以使用它们来索引对象.对于读访问,您可以链索引:

>>> df["A"][(df["B"] > 50) & (df["C"] == 900)]
2    5
3    8
Name: A, dtype: int64
Run Code Online (Sandbox Code Playgroud)

但是你可以让自己陷入麻烦,因为视图和副本之间的区别在于写访问.你可以.loc改用:

>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"]
2    5
3    8
Name: A, dtype: int64
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"].values
array([5, 8], dtype=int64)
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"] *= 1000
>>> df
      A   B    C
0     9  40  300
1     9  70  700
2  5000  70  900
3  8000  80  900
4     7  50  200
5     9  30  900
6     2  80  700
7     2  80  400
8     5  80  300
9     7  70  800
Run Code Online (Sandbox Code Playgroud)

请注意,我不小心输入== 900,而不是!= 900,或~(df["C"] == 900),但我懒得去解决它.为读者锻炼.:^)

  • @yoshiserry:请问这是一个单独的问题.没有人会在旧答案的评论中看到它. (7认同)
  • 如何覆盖(更新)通过选择获得的行? (5认同)
  • 关于`.loc`更新 - 如果你澄清我们获取副本的位置和视图的位置会很好. (3认同)
  • 是否可以过滤pandas数据帧并使用OR运算符.例如,如果有一个列月,你能说df = data ['month'== JAN OR'month'== FEB]?并且可能包括第二列使查询更复杂,newdf其中col_month = jan或feb AND col_day = MONDAY或WENDNESDAY (2认同)
  • 不要忘记括号 - 你会得到奇怪的错误,比如`{TypeError}cannot compare a dtyped [int64] array with a scalar of type [bool]` (2认同)

Nik*_*ris 52

另一种解决方案是使用查询方法:

import pandas as pd

from random import randint
df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9) * 10 for x in xrange(10)],
                   'C': [randint(1, 9) * 100 for x in xrange(10)]})
print df

   A   B    C
0  7  20  300
1  7  80  700
2  4  90  100
3  4  30  900
4  7  80  200
5  7  60  800
6  3  80  900
7  9  40  100
8  6  40  100
9  3  10  600

print df.query('B > 50 and C != 900')

   A   B    C
1  7  80  700
2  4  90  100
4  7  80  200
5  7  60  800
Run Code Online (Sandbox Code Playgroud)

现在,如果要更改A列中的返回值,可以保存其索引:

my_query_index = df.query('B > 50 & C != 900').index
Run Code Online (Sandbox Code Playgroud)

....并用它.iloc来改变它们,即:

df.iloc[my_query_index, 0] = 5000

print df

      A   B    C
0     7  20  300
1  5000  80  700
2  5000  90  100
3     4  30  900
4  5000  80  200
5  5000  60  800
6     3  80  900
7     9  40  100
8     6  40  100
9     3  10  600
Run Code Online (Sandbox Code Playgroud)


Tom*_*iak 29

并记住使用括号!

请记住,&运算符优先于诸如><等运算符。这就是为什么

4 < 5 & 6 > 4
Run Code Online (Sandbox Code Playgroud)

评估为False. 因此,如果您使用pd.loc,则需要在逻辑语句周围加上括号,否则会出现错误。这就是为什么要这样做:

df.loc[(df['A'] > 10) & (df['B'] < 15)]
Run Code Online (Sandbox Code Playgroud)

代替

df.loc[df['A'] > 10 & df['B'] < 15]
Run Code Online (Sandbox Code Playgroud)

这将导致

类型错误:无法将 dtyped [float64] 数组与 [bool] 类型的标量进行比较


小智 7

您可以使用 Pandas,它有一些内置函数进行比较。因此,如果您想选择满足“B”和“C”条件的“A”值(假设您想要返回 DataFrame pandas 对象)

df[['A']][df.B.gt(50) & df.C.ne(900)]

df[['A']] 将以 DataFrame 格式返回 A 列。

pandas 'gt' 函数将返回 B 列大于 50 的位置,'ne' 将返回不等于 900 的位置。