1

我是 Python 和脚本的新手。

我有一个包含 12 列和数千行的表格的巨大 csv 文件,在 Excel 中看起来像这样(注意 5 个连续的管道符号表示一个新单元格,因此此示例由三行和三列组成):

G",'32','0','0.98%',"1E0 ||||| G”、“32”、“0”、“1%”、“1E0 ||||| A", '48', '47', '97.92%', "7.6145E-27

G”、“32”、“0”、“12%”、“1E0 ||||| G”、“32”、“0”、“3%”、“1E0 ||||| A”、“1”、“47”、“97.9%”、“7.6145E-27

G”、“32”、“0”、“0%”、“1E0 ||||| G", '32', '32', '0%', "1E0 ||||| A”、“1”、“47”、“9.92%”、“7.6145E-27

可以看出,每个单元格由五个逗号分隔的元素组成。我只对倒数第二个元素(具有百分比值的元素)感兴趣。请注意此值如何可以有小数或没有小数。所以这是我编写的代码,用于搜索第四个元素并将其写入一个新文件,其中其他元素被丢弃。

import sys
import csv
import re

with open(sys.argv[1],"r") as f_input:
   read_f_input = csv.reader(f_input, delimiter=',')
   with open("f_output.csv", "wt") as f_output:
      f_outputwriter=csv.writer(f_output, delimiter=',')
      for row in read_f_input:
         genotype = re.search(r"[\d+\.]+%", [row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11]])
         result= genotype.group(0)
         f_outputwriter.writerow([result])

由于倒数第三行,此脚本不起作用: genotype = ... 如果我只在单个列上执行此操作(忽略其他 11 列),我已经让脚本工作,但我想执行同时对所有 12 列进行正则表达式操作,并以相同的表格格式写入结果。有谁知道我怎么能做这个棘手的转变?提前致谢!

4

3 回答 3

1

你想要的数据不就是row[3],row[7]row[11]吗?似乎您已经知道您想要哪些列,因为所有行都是相同的,因此无需尝试使用正则表达式查找所需的列。另外,当然,正则表达式不会搜索列表,因此您必须将它们重新加入字符串,但在这种情况下,为什么要在您要加入时使用 CSV 阅读器将其拆分它回来搜索吗?简而言之,我看不出正则表达式与您声明的目标有什么关系,我相信您可能想多了。

于 2012-05-10T23:39:59.473 回答
1

如果数字总是与百分号绑定,您可以使用它re.findall()来获取元素列表:

import csv
import re

fnamein = 'data.csv'
fnameout = 'output.csv'
rex = re.compile(r"'(\d*\.?\d*)%")  # an int/float element with percent sign

with open(fnamein, 'r') as fin, open(fnameout, 'w', newline='') as fout:
    writer = csv.writer(fout)
    for line in fin:
        row = rex.findall(line)         # all elements with percent sign
        row2 = [float(e) for e in row]  # converted explicitly if needed
        writer.writerow(row2)           # write to the output CSV

如果data.csv包含问题中的行,则output.csv包含以下结果:

0.98,1.0,97.92
12.0,3.0,97.9
0.0,0.0,9.92

这适用于 Python 3。对于 Python 2,open(fnameout, 'wb')用于打开输出文件(即二进制模式和 no newline)。

[稍后编辑]rex是编译后的正则表达式,其中百分号前的数字形成一个组 - 请参阅 周围的括号(\d*\.?\d)*。医生

如果模式中存在一个或多个组,则返回组列表...

因此,rex.findall()返回百分号后面的数字,而不是百分号本身。换句话说,row包含数字作为字符串文字(即数字的字符串表示),但不存在百分号。

采用row2 = [float(e) for e in row]字符串表示的数字row并将每个元素转换e为浮点数(即从字符串到实数)。

writer接受浮点数并将它们转换为字符串,用逗号分隔子字符串,然后将它们写入文件。

于 2012-05-11T07:00:44.567 回答
0

不知道大家有没有找到自己喜欢的解决方案,不过我用了大约 10 分钟就写好了下面的代码。您应该能够立即运行它,如下所示:

python process_data.py --file=data.txt

输出

G",'32','0','1.960000.2%',"1E0 ||||| G", '32', '0','2.000000.2%', "1E0 ||||| A”、“48”、“47”、“195.840000.2%”、“7.6145E-27 G”、“32”、“0”、“24.000000.2%”、“1E0 ||||| G", '32', '0','6.000000.2%', "1E0 ||||| A”、“1”、“47”、“195.800000.2%”、“7.6145E-27 G”、“32”、“0”、“0.000000.2%”、“1E0 ||||| G", '32', '32','0.000000.2%', "1E0 ||||| A"、'1'、'47'、'19.840000.2%'、"7.6145E-27

我只是将代码打印出来,但您可以在遍历每一行时轻松使用 csv.writer 或 file.writeline。下面代码的好处在于,只要您知道单元格分隔符和所需值的位置,一行上有多少个单元格并不重要,您可以在一行上放置任意数量的单元格单行。

删除 % 有点小技巧,但是如果您知道数据格式,那么您应该是安全的。您还可以在转换为 float() 的过程中抛出异常块,并跟踪您运行时遇到的错误数。

#!/usr/bin/python

import os, sys, pdb, re
# NOTE: This has been deprecated you should use ArgumentParser
from optparse import OptionParser

__version__ = '$Id$'

DEFAULT_CELL_SEP = '|||||'
DEFAULT_CELL_COL_SEP = ','

parser = OptionParser(version=__version__, usage='Usage: %prog --fille=data_file [--      csep=cell_seperator --ccsep=cell_col_seperator]')
parser.add_option('-f','--file',dest='data_file', 
              help='File to process')
parser.add_option('--csep',dest='cell_sep', default=DEFAULT_CELL_SEP,
              help='Cell Separator')
parser.add_option('--ccseip', dest='cell_col_sep', default=DEFAULT_CELL_COL_SEP,
              help='Column Separator for each cell')

def process_col_four(cell, cell_col_sep=DEFAULT_CELL_COL_SEP, suffix='%'):
    cols = cell.split(cell_col_sep)
    # Do what you need to do...
    # pdb.set_trace()
    col_4 = cols[3].replace(' ','')
    col_4 = float(col_4[1:-2])
    col_4 = col_4 *2
    cols[3] = "'%f.2%s'" % (col_4, suffix)
    return ','.join(cols)
    # return cols

def main(data_file, cell_sep=DEFAULT_CELL_SEP, cell_col_sep=DEFAULT_CELL_COL_SEP):
    data_dir = os.path.dirname(data_file)
    output_file, ext = os.path.splitext(os.path.basename(data_file))
    output_file = output_file + '_recode' + ext
    output_path = os.path.join(data_dir, output_file)

    with open(data_file, 'r') as data_reader:
        for line in data_reader:
            cells = line.strip().split(cell_sep)
             new_cells = map(process_col_four, cells)
             # pdb.set_trace()
             new_line = cell_sep.join([cell for cell in new_cells])
             print new_line


if __name__ == '__main__':
    (options, args) = parser.parse_args()
    if not options.data_file:
        parser.print_usage()
        sys.exit(1)

    main(options.data_file, options.cell_sep, options.cell_col_sep)
于 2012-05-12T22:50:10.670 回答