从 pandas.DataFrame 中使用复杂标准进行选择
- 2024-12-11 08:48:00
- admin 原创
- 136
问题描述:
例如我有简单的 DF:
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)]})
我可以使用 Pandas 的方法和习语从“A”中选择出与“B”对应的值大于 50,与“C”对应的值不等于 900 吗?
解决方案 1:
当然可以!设置:
>>> 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
我们可以应用列操作并获取布尔 Series 对象:
>>> 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)
或者
>>> (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
[更新,切换到新样式.loc
]:
然后我们可以使用这些来索引对象。对于读取访问,您可以链接索引:
>>> df["A"][(df["B"] > 50) & (df["C"] != 900)]
2 5
3 8
Name: A, dtype: int64
但是,由于视图和副本执行此操作以获得写访问权限之间存在差异,因此您可能会陷入麻烦。您可以改用.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
解决方案 2:
另一种解决方案是使用查询方法:
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
现在,如果您想更改 A 列中的返回值,您可以保存它们的索引:
my_query_index = df.query('B > 50 & C != 900').index
....并用来.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
解决方案 3:
记得使用括号!
请记住,&
运算符优先于诸如>
或<
等运算符。这就是为什么
4 < 5 & 6 > 4
计算结果为False
。因此,如果您使用pd.loc
,则需要将逻辑语句括在括号中,否则会出错。这就是为什么这样做的原因:
df.loc[(df['A'] > 10) & (df['B'] < 15)]
而不是
df.loc[df['A'] > 10 & df['B'] < 15]
这将导致
TypeError:无法将 dtyped [float64] 数组与类型为 [bool] 的标量进行比较
解决方案 4:
您可以使用 pandas,它有一些内置函数用于比较。因此,如果您想选择满足“B”和“C”条件的“A”值(假设您想要返回 DataFrame pandas 对象)
df[['A']][df.B.gt(50) & df.C.ne(900)]
df[['A']]
将以 DataFrame 格式返回 A 列。
pandasgt
函数将返回 B 列中大于 50 的位置,并ne
返回不等于 900 的位置。
解决方案 5:
将每个条件分配给一个变量可能会更具可读性,特别是当它们有很多(可能具有描述性名称)并使用按位运算符(例如 (&
或|
)将它们链接在一起时。另外,您无需担心括号,()
因为每个条件都是独立评估的。
m1 = df['B'] > 50
m2 = df['C'] != 900
m3 = df['C'].pow(2) > 1000
m4 = df['B'].mul(4).between(50, 500)
# filter rows where all of the conditions are True
df[m1 & m2 & m3 & m4]
# filter rows of column A where all of the conditions are True
df.loc[m1 & m2 & m3 & m4, 'A']
或者将条件放在列表中并通过bitwise_and
from numpy
(包装器&
)减少它。
conditions = [
df['B'] > 50,
df['C'] != 900,
df['C'].pow(2) > 1000,
df['B'].mul(4).between(50, 500)
]
# filter rows of A where all of conditions are True
df.loc[np.bitwise_and.reduce(conditions), 'A']
相关推荐
热门文章
项目管理软件有哪些?
热门标签
云禅道AD