簡體   English   中英

在bash中對csv列進行排序,將bash輸出讀入python變量

[英]Sorting csv columns in bash, reading bash output into python variables

嗨,我在多個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唯一的解決方案(剪切,awk,數組?!?),但無法弄明白。 另外,我不喜歡將bash命令寫入文件然后將它們讀入python變量的工作。 我可以直接將它們讀入變量,還是有更好的解決方案來解決這個問題? (可能是perl等...但我真的對bash解決方案很感興趣..)

非常感謝你!!

一個快速的單行將是:

grep -a "63[789]\...;" data.csv | sort -n -r -t ';' -k 2 | head --lines=1

這只是根據第二列以數字方式對文件進行排序,然后打印出第一行。 希望有所幫助。

如果您要使用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
$ 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

如果您有大量數據,那么您不希望所有數據存儲到內存中,然后對其進行排序以獲得最大值。 這種方法在計算時間復雜度和存儲器方面都是低效的

您可以簡單地解析文件並在運行中計算所需的值。 一種快速純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('.')):

這是我用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)

很好,非常感謝,Hakop Palyan !!

現在是否有關於如何從所有csv文件中獲取此數據集並將其作為新文件收集到某處的技巧? 就像是

 find . -name '*.csv' -print0 | xargs -0 grep -a "63[789]\...;" | sort -n -r -t ';' -k 2 | head --lines=1

這個只打印第一行,我需要迭代單個文件並收集數據集...

我知道你正在尋找一個基於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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM