python - 将过滤器应用于表的 Pythonic 方式
问题描述
我有两张桌子。一个数据表和一个过滤器表。我想在数据表上应用过滤表以仅选择某些记录。当过滤器表的列中有 # 时,过滤器将被忽略。此外,可以使用 | 应用多个选择。分隔器。
我使用带有一堆 & 和 | 的 for 循环实现了这一点 条件。但是,鉴于我的过滤表很大,我想知道是否有更有效的方法来实现这一点。我的过滤器表如下所示:
import pandas as pd
import numpy as np
f = {'business':['FX','FX','IR','IR','CR'],
'A/L':['A','L','A','L','#'],
'Company':['207|401','#','#','207','#']}
filter = pd.DataFrame(data=f)
filter
数据表如下所示:
d = {'business': ['FX','a','CR'],
'A/L': ['A','A','L'],
'Company': ['207','1','2']}
data = pd.DataFrame(data=d)
data
最后过滤器看起来像:
for counter in range (0, len(filter)):
businessV = str(filter.iat[counter,0])
ALV = str(filter.iat[counter,1])
CompanyV = str(filter.iat[counter,2])
businessV1 = businessV.split("|", 100)
ALV1 = ALV.split("|", 100)
CompanyV1 = CompanyV.split("|", 100)
businessV2 = ('#' in businessV1)| (data['business'].isin(businessV1))
ALV2 = ('#' in ALV1)|(data['A/L'].isin(ALV1))
CompanyV2 = ('#' in CompanyV1)| (data['Company'].isin(CompanyV1))
final_filter = businessV2 & ALV2 & CompanyV2
print(final_filter)
我试图找到一种更有效的方法来使用过滤器表中的过滤器选择数据表中的第一行和最后一行。
具体来说,我想知道如何:
- 处理过滤表有更多列的情况
- 当前代码对过滤表中的每一行遍历数据表中的每一行一次。对于大型数据集,这需要太多时间,而且对我来说似乎效率不高。
解决方案
这是一个相当复杂的问题。我将首先通过复制包含'|'
. 为了限制无用行的数量,我首先将包含 a'#'
和其他值的任何内容替换为单个'#'
.
完成此操作后,可以从带有 的业务表中选择行merge
,前提是合并不包含锐利的列。
代码可以是:
# store the original column names
cols = filter.columns
# remove any alternate value if a # is already present:
tosimp = pd.DataFrame({col: filter[col].str.contains('#')&
filter[col].str.contains('\|')
for col in cols})
# add a column to store in a (hashable) tuple the columns with no '#'
filter['wild'] = filter.apply(lambda x: tuple(col for col in cols
if x[col] != '#'), axis=1)
# now explode the fields containing a '|'
tosimp = pd.DataFrame({col: filter[col].str.contains('\|')
for col in filter.columns})
# again, store in a new column the columns containing a '|'
tosimp['wild'] = filter.apply(lambda x: tuple(col for col in cols
if '|' in filter.loc[x.name, col]),
axis=1)
# compute a new filter table with one single value per field (or #)
# by grouping on tosimp['wild']
dfl = [filter[tosimp['wild'].astype(str)=='()']]
for k, df in filter[tosimp['wild'].astype(str)!='()'].groupby(tosimp['wild']):
for ix, row in df.iterrows():
tmp = pd.MultiIndex.from_product([df.loc[ix, col].split('|')
for col in k], names=k).to_frame(None)
l = len(tmp)
dfl.append(pd.DataFrame({col: tmp[col]
if col in k else [row[col]] * l
for col in filter.columns}))
filter2 = pd.concat(dfl)
# Ok, we can now use that new filter table to filter the business table
result = pd.concat([data.merge(df, on=k, suffixes=('', '_y'),
right_index=True)[cols]
for k, df in filter2.groupby('wild')]).sort_index()
限制:
- 预处理迭代按数据帧分组并使用
iterrows
调用:在大型过滤表上可能需要一些时间 - 当前算法根本不处理包含
'#'
其所有字段的行。如果这是一个可能的用例,则必须在任何其他处理之前对其进行搜索。无论如何,在这种情况下,将保留业务表中的任何行。
线路说明pd.concat(...
:
[... for k, df in filter2.groupby('wild')]
:将过滤器数据帧拆分为子数据帧,每个子数据帧具有不同的wild
值,即一组不同的非#字段data.merge(df, on=k, suffixes=('', '_y'), right_index=True)
:将每个子过滤器数据框与非#字段上的数据数据框合并,即从与这些过滤器行之一匹配的数据数据框中选择行。保留数据数据框的原始索引...[cols]
只保留相关字段pd.concat(...)
连接所有这些部分数据帧... .sort_index()
根据其索引对连接的数据帧进行排序,该索引是通过构建原始数据数据帧的索引
推荐阅读
- python - AttributeError:调用 Clock.schedule_interval 函数时,“NoneType”对象在 Kivy 中没有属性“ids”
- javascript - 为什么 onClick() 没有响应
- maven - Jenkins 中缺少“将工件部署到 Maven 存储库”选项
- react-redux - 如何让 React 组件智能地在用户交互时调度 Redux 动作,而不传递不影响视觉外观的道具
- swift - 调用 Firebase 后自行调整单元格大小
- javascript - 正则表达式如何获取字符串中某个单词之后的内容?
- javascript - 如何在对象中推送数据?
- lambda - Spring 集成 DSL - CharacterStreamWritingMessageHandler
- r - R在彼此之间循环列表中的所有向量
- javascript - 上下文提供程序中的 componentDidMount() 状态更改未触发子组件的重新渲染