【问题标题】:bash or python csv multiple field handling [closed]bash或python csv多字段处理[关闭]
【发布时间】:2013-03-22 22:04:59
【问题描述】:

我正在开展一个项目,该项目涉及基于 csv 文件的一些变量/参数创建输出,我正在寻找处理它的最佳方法。

我有一个中等大小的 csv 文件,如下所示:

input.csv

B|Person1|3000
A|Person2|3000
C|Person3|5400
A|Person4|1700
C|Person5|9400
D|Person6|2400
B|Person7|2000
A|Person8|3400
A|Person9|1000
A|Person10|2500
A|Person11|3000

我希望输出看起来像:

输出.csv

A|Person2|3000
A|Person4|1700
B|Person1|3000
B|Person7|2000
C|Person3|5400
D|Person6|2400

但输出只能是 6 人 (AABBCD) 并且第 3 列的总和 input.csv 的顶行向下创建输出:

  1. 如果行为空,则根据字母 A-D(Column1)填写人,[可选]忽略第 3 列的总和。
  2. 如果行不为空且第 3 列的总和小于 1800 - 跳过(继续)。
  3. 如果行不为空且第 3 列的总和超过 1800,则替换最大值(继续)。
  4. [可选] 完成后,重新检查是否可以用更高的值替换任何人;本质上是创建一个 18000 年以下最有价值的人的名单。

注意:所有6个参数都必须根据它们的第1列位置填写。

我起初想生成一个 output.csv 文件,其中第一列包含 AABBCD,并使用 awk 匹配和条件语句添加行。然后我开始研究使用 awk 数组(将 3 列传递给 3 个数组并根据索引分配值)...

但是现在,似乎 python 可能是处理 csv 文件时要走的路,但在使用 python 编写脚本时,我仍然是新手;您能否推荐适当的路径来产生所需的输出?

提前非常感谢,这让我发疯了。

编辑: 简单地说 - 仅匹配前 6 个(AABBCD:带有 2As、2Bs、1C、1D)并且第 3 列的最终总和

【问题讨论】:

  • Python 一路走好!免责声明:我喜欢 Python。现在有一个更喜欢 Python 的实际原因:Python 代码可以编写成跨平台的,虽然你可以在 cygwin 上使用 bash,但谁愿意这样做?
  • 输出是否必须是您指定的那 6 个? 2 和 3 是什么意思,即即使您说要跳过 1800 以下的值,您的 output.csv 的值也超过 1800。最后,“替换最高值”是指将当前行添加到顶部?
  • @AndreasGS - 输出必须是由 col1 中的字母字面关联的组。我想你可能读错了,我正在寻找 col3 的总和等于或低于 18,000(不是 1800)。如果#1 填补了所有职位并且超过 18,000,#3 只是看起来解决了这个问题。为了纠正这个问题,#3 将通过替换较大的整数来选择性地降低总和。希望这可以清除它。感谢您的评论。
  • @bernie - 我承认,我一直在使用 cygwin...哈哈,我在我的 Fedora 盒子上启动了这个脚本(因此我使用 bash / awk 来生成上述文件)。感谢您的输入!我正在研究以下一些建议。

标签: python bash csv if-statement awk


【解决方案1】:

这里有一段原始代码,您可以从中轻松调整以满足您的需要

import csv
with open('input.csv') as f_in, open('output.csv', 'w') as f_out :
   csv_r = csv.reader(f_in, delimiter='|')
   csv_w = csv.writer(f_out, delimiter='|')
   col_sum = 0
   for row in csv_r :
       if len(row) == 0 :
           continue
       elif len(row) == 3 :
           letter, person, value = row
           col_sum += int(value)
           if col_sum < 1800 :
               csv_w.writerow(row)
           else :
               row[2] = 0
               csv_w.writerow(row)

【讨论】:

  • 看来python是我需要使用的......我希望我能更好地读/写它。我会考虑改变它以满足我的需求。谢谢!
  • 如果我没记错的话,这将处理与检查 col_sum 相关的所有事情,并将总数保持在 18k 以下。但是我怎么能限制这个代码只产生 6 个 2A、2B、1C、1D 的插槽呢?目前正在更多地研究 csv...谢谢!
【解决方案2】:

这也是一个你可以尝试的 awk 版本:

awk -F\| '
  NR<=set{
    A[NR]=$0
    total+=$NF
    values[NR]=$3
    next
  }

  total>treshold{
    max=0
    for(i in values) if (values[i]>max){
      max=values[i]; j=i
    }
    if ( max > $NF) {
      A[j]=$0
      total+=$NF-max
      values[j]=$NF
    }
  }

  END{
    print total; for(i in A) print A[i]
  }
' set=6 treshold=18000 file | sort

【讨论】:

  • 谢谢! (免责声明:仍在学习)我没有看到将输出限制为 2A、2B、1C 和 1D 中的 6 个的东西。除非 A[NR]=$0 这样做。再次感谢。
【解决方案3】:

如果我理解正确的话……就这样吧。

import csv

def get_subset(rows):
    sub_sets = []
    #get all combinations of rows
    for L in range(0, len(rows)+1):
        for subset in itertools.combinations(rows, L):
            sub_sets.append(subset)

    #get all combinations less than six
    lessthansix = filter(lambda x: True if len(x) <= 6 else False, sub_sets)
    #get all combinations less than or equal to max
    lessthanmax = filter(lambda x: True if sum([int(col[2]) for col in x]) <= 18000 else False, lessthansix)
    #sort the less than max groups by sum of col 3
    closesttomax = sorted(lessthanmax, reverse=True, key=lambda x: sum([int(col[2]) for col in x])) 

    return closesttomax[0]

with open("test.csv", 'r') as f:
    reader = csv.reader(f, delimiter="|")
    #filter out all rows that have col 3 less than 1800
    rows = [row for row in reader if int(row[2]) > 1800]
    subset = get_subset(rows)
    sorted_rows = sorted(subset, key=lambda x: x[0])
    with open("out.csv", 'w') as o:
        writer = csv.writer(o)
        print sorted_rows
        print sum([int(col[2]) for col in sorted_rows])
        for row in sorted_rows:
            writer.writerow(row)

【讨论】:

  • 这接近我所需要的。问题在于它给出了 18000 以下的最佳组合。我需要它来填充所有 6 AABBDC 行。我不是 python 大师,所以我可能错过了一些东西,但我的输出是:[['B', 'Person1', '3000'], ['C', 'Person3', '5400'], ['C ', 'Person5', '9400']] 17800。我更感兴趣的是在所有低于 18000 的地方使用索引最高的人。谢谢,我会对此进行更多研究,看看是否可以调整它。
  • @LaidBach 您提供的数据集中没有不超过 18000 的 6 个组合。
  • 嗯,使用数据集,我的示例输出加起来不到 18000。我将继续使用更大的数据集测试您提供的代码。我正在使用 python 更多地研究 CSV 和 itertools。再次感谢您的帮助。此外,我在过滤器中看到一个错字为 1800 而不是 18000 - 让我看看它做了什么调整。谢谢!更新:将值更改为 18000 并将行参数更改为 大于 18000)有效。现在我唯一担心的是它是否会将更大的数据集排序为只有 2As、2Bs、1C、1D。 (测试..)谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 2014-03-21
  • 2017-11-19
  • 2014-10-06
  • 2015-09-14
相关资源
最近更新 更多