我有以下阈值:
for a_x: red=10 blue=5
for a_y: red=50 blue=15
for b_x: red=8 blue=4
for b_y: red=40 blue=10
这是我拥有的数据框:
type x1 x2 x3 y1 y2 y3 z
a 1 3 5 11 13 9 qaz
a 2 7 9 23 67 35 qeq
a 7 9 13 36 24 8 rfc
b 10 3 5 51 19 10 qwe
b 5 4 2 21 12 11 erg
b 1 2 3 9 7 8 gbt
现在对于类型为a的行,我想对列名称中包含x的任何列和包含y的a_y阈值列使用a_x阈值。
类似地,对于type = b的行,我想对包含x的列使用b_x阈值,而对于包含y的列使用b_y阈值。
最终,我想创建两个新的数据框,红色和蓝色,其中包含违反红色阈值的所有行(值> =阈值时被突破),仅蓝色阈值被违反(因此,如果红色阈值被违反则无需检查蓝色阈值,因为它将仅是红色的一部分,而不是蓝色。
因此,最后我们将具有以下数据框:
红色:
type x1 x2 x3 y1 y2 y3 z
a 2 7 9 23 67 35 qeq
a 7 9 13 36 24 8 rfc
b 10 3 5 51 19 10 qwe
蓝色:
type x1 x2 x3 y1 y2 y3 z
a 1 3 5 11 13 9 qaz
b 5 4 2 21 12 11 erg
为
type x1 x2 x3 y1 y2 y3 z
a 1 3 5 11 13 9 qaz -> x3 breaches blue
a 2 7 9 23 67 35 qeq -> y2 breaches red
a 7 9 13 36 24 8 rfc -> x3 breaches red
b 10 3 5 51 19 10 qwe -> x1, y1 breaches red
b 5 4 2 21 12 11 erg -> x1, x2, y1, y2, y3 breaches blue
b 1 2 3 9 7 8 gbt -> no breach
现在,显然,我可以遍历所有行和列并检查阈值违规,但是必须有一种更好的方法!
答案 0 :(得分:1)
首先,我为嵌套字典创建条件:
d = {'a_x': {'red':10, 'blue':5},
'a_y': {'red':50, 'blue':15},
'b_x': {'red':8, 'blue':4},
'b_y': {'red':40, 'blue':10}}
更好的格式是将red
和blue
的值分别分配给外部字典:
from collections import defaultdict
d1 = defaultdict(dict)
for k, v in d.items():
for k1, v1 in v.items():
d1[k1][k] = v1
print (d1)
defaultdict(<class 'dict'>, {'red': {'a_x': 10, 'a_y': 50, 'b_x': 8, 'b_y': 40},
'blue': {'a_x': 5, 'a_y': 15, 'b_x': 4, 'b_y': 10}})
然后按每个字典循环,并按boolean indexing
进行过滤,并用k
划分_
值:
red = [df.loc[df['type'].eq(k.split('_')[0]),
df.columns.str.startswith(k.split('_')[1])] >= v for k, v in d1['red'].items()]
然后通过concat
将掩码连接在一起,并通过DataFrame.any
测试至少一行是否匹配:
mask_red = pd.concat(red).any(level=0).any(axis=1)
# print (mask_red)
blue = [df.loc[df['type'].eq(k.split('_')[0]),
df.columns.str.startswith(k.split('_')[1])] >= v for k, v in d1['blue'].items()]
mask_blue = pd.concat(blue).any(level=0).any(axis=1)
# print (mask_blue)
最后一个过滤器匹配红色值:
df1 = df[mask_red]
print (df1)
type x1 x2 x3 y1 y2 y3 z
1 a 2 7 9 23 67 35 qeq
2 a 7 9 13 36 24 8 rfc
3 b 10 3 5 51 19 10 qwe
红色DataFrame中已经使用了排除的蓝色值:
df2 = df[mask_blue & ~mask_red]
print (df2)
type x1 x2 x3 y1 y2 y3 z
0 a 1 3 5 11 13 9 qaz
4 b 5 4 2 21 12 11 erg
为避免可能重复代码,请对字典蒙版使用字典理解:
d = {'a_x': {'red':10, 'blue':5},
'a_y': {'red':50, 'blue':15},
'b_x': {'red':8, 'blue':4},
'b_y': {'red':40, 'blue':10}}
d1 = defaultdict(dict)
for k, v in d.items():
for k1, v1 in v.items():
d1[k1][k] = v1
print (d1)
defaultdict(<class 'dict'>, {'red': {'a_x': 10, 'a_y': 50, 'b_x': 8, 'b_y': 40},
'blue': {'a_x': 5, 'a_y': 15, 'b_x': 4, 'b_y': 10}})
masks = {k1: pd.concat([df.loc[df['type'].eq(k.split('_')[0]),
df.columns.str.startswith(k.split('_')[1])] >= v
for k, v in v1.items()]).any(level=0).any(axis=1)
for k1, v1 in d1.items()}
print (masks)
{'red': 0 False
1 True
2 True
3 True
4 False
5 False
dtype: bool, 'blue': 0 True
1 True
2 True
3 True
4 True
5 False
dtype: bool}
df1 = df[masks['red']]
print (df1)
type x1 x2 x3 y1 y2 y3 z
1 a 2 7 9 23 67 35 qeq
2 a 7 9 13 36 24 8 rfc
3 b 10 3 5 51 19 10 qwe
df2 = df[masks['blue'] & ~masks['red']]
print (df2)
type x1 x2 x3 y1 y2 y3 z
0 a 1 3 5 11 13 9 qaz
4 b 5 4 2 21 12 11 erg
答案 1 :(得分:0)
您可以声明一些条件过滤器,例如:
a_red_filter = (df[type] == 'a') & (df[['x1','x2','x3']] < [10]*3) &
(df[['y1','y2','y3']]<[50]*3)
b_red_filter = (df[type] == 'b') & (df[['x1','x2','x3']] < [8]*3) &
(df[['y1','y2','y3']] <[40]*3)
,如果您执行命令:
df[a_red_filter | b_red_filter]
因此,您将获得用于红点的数据框:
type x1 x2 x3 y1 y2 y3 z
a 2 7 9 23 67 35 qeq
a 7 9 13 36 24 8 rfc
b 10 3 5 51 19 10 qwe
显然与蓝色相同
答案 2 :(得分:0)
希望您能比我以前发布的烂书更好地阅读
#reshape table and create column of just the alphabets
M = (df.melt(['type','z'])
.assign(letters=lambda x: x.variable.str[0])
)
red_a = M.query('type=="a" and ((letters=="x" and value >=10) or (letters=="y" and value >=50))')
red_b = M.query('type=="b" and ((letters=="x" and value >=8) or (letters=="y" and value >=40))')
blue_a = M.query('type=="a" and ((letters=="x" and value >=5) or (letters=="y" and value >=15))')
blue_b = M.query('type=="b" and ((letters=="x" and value >=4) or (letters=="y" and value >=10))')
red_only = (pd.concat([red_a,red_b])
.filter(['type','z'])
.drop_duplicates('z')
)
red_only_z = red_only["z"].tolist()
blue_only = (pd.concat([blue_a,blue_b])
.filter(['type','z'])
#if row already belongs in red, filter it out
.query('z != @red_only_z')
.drop_duplicates('z')
)
#extract tables from the original dataframe
cond_red = df['z'].isin(red_only_z) & (df['type'].isin(red_only['type']))
cond_blue = df['z'].isin(blue_only['z']) & (df['type'].isin(blue_only['type']))
red_table = df.loc[cond_red]
blue_table = df.loc[cond_blue]
print(blues)
type x1 x2 x3 y1 y2 y3 z
0 a 1 3 5 11 13 9 qaz
4 b 5 4 2 21 12 11 erg
print(reds)
type x1 x2 x3 y1 y2 y3 z
1 a 2 7 9 23 67 35 qeq
2 a 7 9 13 36 24 8 rfc
3 b 10 3 5 51 19 10 qwe