Python 我应该如何使用多种过滤器类型过滤CSV的大型(70+;MB)文本文件
tl;dr:我想更改列值,条件是在600k行csv中有3个不同过滤器的匹配列条目,怎么做? 我有几个数据文件,超过600000行。它们看起来像这样:Python 我应该如何使用多种过滤器类型过滤CSV的大型(70+;MB)文本文件,python,bash,Python,Bash,tl;dr:我想更改列值,条件是在600k行csv中有3个不同过滤器的匹配列条目,怎么做? 我有几个数据文件,超过600000行。它们看起来像这样: random.website.com|1000002644|FunGRP_1000009280_OT|5556667777@random.website.com|User|5556667777|main|Y|6557|main||6557| 我想在匹配项中将第8列的值Y/N更改为N 我有一个列2(企业)3(集团)和6(电话号码)的过滤器列表,存储
random.website.com|1000002644|FunGRP_1000009280_OT|5556667777@random.website.com|User|5556667777|main|Y|6557|main||6557|
我想在匹配项中将第8列的值Y/N
更改为N
我有一个列2(企业)3(集团)和6(电话号码)的过滤器列表,存储在换行符分隔的文本文件中,如下所示:
电话号码
5553690049
5553690050
5553690052
...
企业
Loud-YPOxXTFF
res-http
1700000004
...
团体
FunGRP_1000009280_OT
1300000004_CollabGrp_1
HostedVKL_1300000035_SA
...
现在我在bash中有一个程序,它迭代数据中的每个条目,提取我想用awk过滤的列(这意味着1800k个awk调用),然后在每个要检查的东西上循环三次,然后在循环中读取每个过滤器,然后检查过滤器是否匹配该项。如果是,则awk行(第4 awk)以替换第8列,并将其填充到输出文件中。如果没有与该行匹配的筛选器,则只需将未更改的行放入输出文件中。虽然效率极低,但它确实有效。代码如下:
filter () {
while read -r entry || [[ -n "$entry" ]]; do
phone="$(echo "$entry" | awk -F "|" '{ print $6 }')"
group="$(echo "$entry" | awk -F "|" '{ print $3 }')"
enterprise="$(echo "$entry" | awk -F "|" '{ print $2 }')"
to_test=("$phone" "$group" "$enterprise")
filters=("$NUMBER_FILTER_FILE" "$GROUP_FILTER_FILE" "$ENTERPRISE_FILTER_FILE")
count=-1
matched=""
for item in "${to_test[@]}"; do
count=$(( count+1 ))
if [[ -n "$item" ]] && [[ -f "${filters[$count]}" ]]; then
while read -r filter || [[ -n "$filter" ]]; do
if [[ "$item" = "$filter" ]]; then
echo "$entry" | awk -F "|" 'BEGIN {OFS = FS} $8="N" {print}' >> "$WORKING$OUTPUTFILE"
matched="true"
continue 2
fi
done < "${filters[$count]}"
fi
done
# If no filter matches, put the original entry in the output
[[ -z "$matched" ]] && echo "$entry" >> "$WORKING$OUTPUTFILE"
done < "$WORKING$UNFILTEREDOUTPUTFILE"
}
我正在更新的原始程序是用bash编写的,这就是为什么我继续尝试用shell脚本解决这个问题,但我不是bash的向导,所以我开始研究python+pandas来实现这一点,因为我觉得这应该更容易。任何建议、策略或想法都会有所帮助。谢谢。如果我理解正确,以下几点可以:
awk "
BEGIN {FS = OFS = \"|\"}
FILENAME=="\"$NUMBER_FILTER_FILE\"" {phone[\$0]++; next}
FILENAME=="\"$GROUP_FILTER_FILE\"" {group[\$0]++; next}
FILENAME=="\"$ENTERPRISE_FILTER_FILE\"" {enterprise[\$0]++; next}
FILENAME=="\"$WORKING$UNFILTEREDOUTPUTFILE\"" {
if (phone[\$6] || group[\$3] || enterprise[\$2]) \$8 = \"N\"
print
}" "$NUMBER_FILTER_FILE" "$GROUP_FILTER_FILE" "$ENTERPRISE_FILTER_FILE" "$WORKING$UNFILTEREDOUTPUTFILE" > "$WORKING$OUTPUTFILE"
恐怕你贴的例子没有提供足够的信息
(例如,1000002644
行的第二个字段与任何行都不匹配
在企业
)中,我做了一些假设。
如果我的代码不能正常工作,如果你能发布我的代码,我将不胜感激
查看我的代码的更多信息。比尔
[解释]关键是我们如何减少计算量。你的原创 代码在中反复扫描筛选文件以查找关键字 主回路冗余且效率低下。我们可以彻底地 通过在
awk
中使用关联数组
来减少冗余。
(请注意,相同的机制在许多语言中使用
不同的名称:Perl中的hash
和Python中的dictionary
,等等)
让我用中的第一行FunGRP\u 100009280\u OT
进行说明
$GROUP\u FILTER\u文件
。通过使用关联数组在单词上做标记
通过说组[“FunGRP\u 100009280\u OT”]++
,我们可以在后记中测试
单词以最小的计算成本包含在列表中
现在让我们回到我的代码。只是为了利用贝壳
变量如$NUMBER\u FILTER\u FILE
等。我已附上awk
脚本
使用双引号,而不是单引号。这可能不是一个标准方案,因为
它需要很多带有反斜杠的转义。(我本该通过的
通过-v
选项显示外壳变量。)
BEGIN
块在读取输入行和
我已将|
分配给输入和输出字段分隔符
- 其余代码在文件中的每个输入行上执行
指定为命令行参数
- 模式
FILENAME==“$NUMBER\u FILTER\u FILE”
测试当前
输入文件是$NUMBER\u FILTER\u file
和下面的块{…}
如果模式匹配,则执行
- 输入行中的单词将自动分配给
awk
变量$0
。然后,$NUMBER\u FILTER\u文件的第一行作为
phone[“5553690049”]++
在上面做上如上所述的标记
- 以下代码基于内容设置每个关联数组
每个文件的名称
- 最后一行以
FILENAME==“$WORKING$UNFILTEREDOUTPUTFILE”
是迭代csv文件的主循环。这条线被分成两部分
用|
分隔的字段,这些字段分配给$1
,$2
。。。
按顺序
- 如果
if(…)
测试为真,则第8个字段$8
设置为“N”
李>
希望这能有所帮助。如果我理解正确,以下几点就行了:
awk "
BEGIN {FS = OFS = \"|\"}
FILENAME=="\"$NUMBER_FILTER_FILE\"" {phone[\$0]++; next}
FILENAME=="\"$GROUP_FILTER_FILE\"" {group[\$0]++; next}
FILENAME=="\"$ENTERPRISE_FILTER_FILE\"" {enterprise[\$0]++; next}
FILENAME=="\"$WORKING$UNFILTEREDOUTPUTFILE\"" {
if (phone[\$6] || group[\$3] || enterprise[\$2]) \$8 = \"N\"
print
}" "$NUMBER_FILTER_FILE" "$GROUP_FILTER_FILE" "$ENTERPRISE_FILTER_FILE" "$WORKING$UNFILTEREDOUTPUTFILE" > "$WORKING$OUTPUTFILE"
恐怕你贴的例子没有提供足够的信息
(例如,1000002644
行的第二个字段与任何行都不匹配
在企业
)中,我做了一些假设。
如果我的代码不能正常工作,如果你能发布我的代码,我将不胜感激
查看我的代码的更多信息。比尔
[解释]
关键是我们如何减少计算量。你的原创
代码在中反复扫描筛选文件以查找关键字
主回路冗余且效率低下。我们可以彻底地
通过在awk
中使用关联数组
来减少冗余。
(请注意,相同的机制在许多语言中使用
不同的名称:Perl中的hash
和Python中的dictionary
,等等)
让我用中的第一行FunGRP\u 100009280\u OT
进行说明
$GROUP\u FILTER\u文件
。通过使用关联数组在单词上做标记
通过说组[“FunGRP\u 100009280\u OT”]++
,我们可以在后记中测试
单词以最小的计算成本包含在列表中
现在让我们回到我的代码。只是为了利用贝壳
变量如$NUMBER\u FILTER\u FILE
等。我已附上awk
脚本
使用双引号,而不是单引号。这可能不是一个标准方案,因为
它需要很多带有反斜杠的转义。(我本该通过的
通过-v
选项显示外壳变量。)<
import pandas as pd
# Load all the data
data = pd.read_csv('input.csv', sep="|", names=['site', 'entreprise', 'group', 'mail', 'name', 'phone', 'a', 'yn', 'b', 'c', 'd', 'e', 'f'])
phones = pd.read_csv('phones.dat', header=None)
entreprises = pd.read_csv('entreprises.dat')
groups = pd.read_csv('groups.dat')
# Define the match function
def match(row):
return row['phone'] in phones.values or row['entreprise'] in entreprises.values or row['group'] in groups.values
# Update the column with match function
data['yn'] = data.apply(match, axis=1)
# Write output
data.to_csv('output.csv', sep="|", header=False, index=False)