您好我在多个csv文件中有大量数据并使用grep过滤掉数据集:
user@machine:~/$ cat data.csv | grep -a "63[789]\...;"
637.05;1450.2
637.32;1448.7
637.60;1447.7
637.87;1451.5
638.14;1454.2
638.41;1448.6
638.69;1445.8
638.96;1440.0
639.23;1431.9
639.50;1428.8
639.77;1427.3
我想弄清楚具有最高计数的数据集,右边的列;然后知道相应的值(左边的;)。在这种情况下,我正在寻找的集合将是638.14; 1454.2
我尝试了不同的东西,结果使用了bash和python的组合,这有效,但不是很漂亮:
os.system('ls | grep csv > filelist')
files = open("filelist")
files = files.read()
files = files.split("\n")
for filename in files[0:-1]:
os.system('cat ' + filename + ' | grep -a "63[6789]\...;" > filtered.csv')
filtered = csv.reader(open('filtered.csv'), delimiter=';')
sortedlist = sorted(filtered_file, key=operator.itemgetter(1), reverse=True)
dataset = sortedlist[0][0] + ';' + sortedlist[0][1] + '\n'
我希望有一个只有bash的解决方案(cut,awk,数组?!?)但是无法理解它。另外,我不喜欢将bash命令写入文件然后将它们读入python变量的工作。我可以直接将它们读入变量,还是有更好的解决方案来解决这个问题? (可能是perl等......但我真的对bash解决方案感兴趣..)
非常感谢!!
答案 0 :(得分:6)
快速的单行将是:
grep -a "63[789]\...;" data.csv | sort -n -r -t ';' -k 2 | head --lines=1
这只是根据第二列以数字方式对文件进行排序,然后打印出第一行。希望有所帮助。
答案 1 :(得分:3)
如果您打算使用Python,那么请使用Python。为什么要将bash命令混合在一起?它使您的代码不可移植/依赖于bash环境。
import os
import glob
import operator
os.chdir("/mypath")
for file in glob.glob("*.csv"):
data=open(file).readlines()
data=[i.strip().split(";") for i in data if i[:3] in ["637","638","639"]]
# data=[i.strip().split(";") for i in data if i[:3] in ["637","638","639"] and isinstance(float(i[:6]),float) ]
sortedlist = sorted(data, key=operator.itemgetter(1), reverse=True)
print "Highest for file %s: %s" % (file,sortedlist[0])
或者,如果您对bash +工具解决方案更感兴趣
find . -type f -name '*.csv' |while read -r FILE
do
grep -a "63[789]\...;" "$FILE" | sort -n -r -t ';' -k 2 | head -1 >> output.txt
done
答案 2 :(得分:1)
$ cat data.csv | grep -a "63[789]\...;" | awk 'BEGIN {FS=";"} $2>max{max=$2; val=$1} END {print "max " max " at " val}'
max 1454.2 at 638.14
答案 3 :(得分:1)
如果您有大量数据,那么您不希望将所有数据存储到内存中,然后排序以获取最大值。关于计算时间复杂度和内存,这种方法效率低。
您可以简单地解析文件并在运行中计算所需的值。一种快速纯Python方法来处理您的问题:
import os, re
os.chdir('/path/to/csvdir')
for f in os.listdir('.'):
dataset, count = 0.0, 0.0
for line in open(f):
if re.search(r'63[6789]\...', line):
d, c = map(float, line.strip().split(';'))
if count < c:
dataset, count = d, c
print f, dataset
通过修改相应的行,此方法还可用于显示最大值列表(如果可以有多个具有最高计数的数据集):
dataset, count = [], 0.0
...
if count < c:
dataset, count = [d], c
elif count == c:
dataset.append(d)
编辑:该脚本假定您的csvdir仅填充包含解析格式的文件。如果要按名称过滤它们,可以使用glob(在名称过滤中具有有限的正则表达式功能):
for f in glob.glob('*.csv'):
或将过滤器应用于os.listdir
:
for f in filter(lambda f: re.match('.*\.csv', f), os.listdir('.')):
答案 4 :(得分:1)
以下是我使用python对csv文件进行排序的代码。它允许您指定多个列,并使用减号按相反顺序排序。
#!/usr/bin/env python
# Usage:
# (1) sort ctb_consolidated_test_id.csv by Academic Year, Test ID, Period, and Test Name, with Test ID in descending order
# sort_csv.py -c "Academic Year" -c "-Test ID" -c "Period" -c "Test Name" ctb_consolidated_test_id.csv
from __future__ import with_statement
from __future__ import print_function
import sys
def multikeysort(items, columns):
from operator import itemgetter
import re
num_re = re.compile(r'^\d+$')
comparers = [
((itemgetter(col[1:].strip()), -1) if col.startswith('-') else (itemgetter(col.strip()), 1))
for col in columns
]
def number_comparable(val1, val2):
return len(val1) != len(val2) and num_re.match(val1) and num_re.match(val2)
def column_comparer(left, right):
for fn, mult in comparers:
val1, val2 = fn(left), fn(right)
if number_comparable(val1, val2):
val1, val2 = int(val1), int(val2)
result = cmp(val1, val2)
if result:
return mult * result
return 0
return sorted(items, cmp=column_comparer)
def sort_csv(filename, columns):
import csv
with open(filename, "r") as f:
reader = csv.DictReader(f)
writer = csv.DictWriter(sys.stdout, reader.fieldnames)
writer.writerow(dict(zip(reader.fieldnames, reader.fieldnames)))
writer.writerows(multikeysort(reader, columns))
if __name__ == '__main__':
from glob import glob
from optparse import OptionParser, make_option
option_list = [
make_option('-c', '--column', dest='columns', action='append', metavar='COLUMN NAME'),
]
parser = OptionParser(option_list=option_list)
(options, args) = parser.parse_args()
filenames = (filename for arg in args for filename in glob(arg))
for filename in filenames:
sort_csv(filename, options.columns)
答案 5 :(得分:0)
很好,非常感谢,Hakop Palyan !!
现在有一个关于如何从所有csv文件中获取此数据集并将其作为新文件收集到某处的技巧?
之类的东西 find . -name '*.csv' -print0 | xargs -0 grep -a "63[789]\...;" | sort -n -r -t ';' -k 2 | head --lines=1
这个只打印第一行,我需要遍历各个文件并收集数据集......
答案 6 :(得分:0)
我知道您正在寻找基于bash的解决方案,但我无法使用csv模块提供一些内容。
import os
import csv
import re
target_re = re.compile(r'^63[789]\.\d\d$')
csv_filenames = [f for f in os.listdir('.') if f.endwith('.csv')]
largest_in_each_file = []
for f in csv_filenames:
largest = (None, 0)
for a,b in csv.reader(open(f, 'rb'), delimiter=';'):
if target_re.match(a) and b > largest[1]:
largest = (a, b)
largest_in_each_file.append(largest)
largest_overall = largest_in_each_file[0]
for largest in largest_in_each_file:
print "%s;%s in %s" % largest
if largest[1] > largest_overall[1]:
largest_overall = largest
print "-" * 10
print "%s;%s in %s is the largest record in all files" % largest_overall