求和 csv 文件中未排序的列列表?

Sum an unsorted list of columns in csv file?

我是 Python 的新手(并且对脚本很生疏,我最近的尝试是 bash 和 Perl 在 2001 年左右),已经尝试搜索 SO - 但老实说没有甚至不知道要寻找什么。我相当确定这是微不足道的 - 我有点惭愧。

我有一个相当大的 CSV 文件(大约 26k 行),采用制表符分隔格式:

name, current_value, current_pct, change_pct
ItemA 2452434324     7,70%        -1,19
ItemB 342331         2,40%        -0,45
ItemC 32412123       3,90%        3,87
ItemD 0              0            -4,52
ItemE 12318231       14,80%       0
ItemA 542312134      1,60%        0,11
ItemC 2423423425     11,21%       -0,01
ItemE 3141888103     30,00%       0
ItemB 78826          1,01%        12,01
ItemA 89937          0,04%        0
...

总共有大约300个"Items"(重复,但顺序不同,有时只出现一次或两次),每个都有一个"current value"(整数,从0到大约 10 亿(或 1 billion/milliard),当前百分比值(目前我不感兴趣),以及与上次读数相比的百分比变化(不同的文件,目前我不感兴趣)。 我想要实现的是每个 Item 的“change_pct”列的总和,因此对于上述示例结果将是:

name    total_pct_change
ItemA   -1,08
ItemB   11,56
ItemC   3,86
ItemD   -4,52
ItemE   0

我打算创建一个 items 的列表,然后将 row[3] 的值相加,但我失败了。 我现在拥有的:

import csv, sys, string
xlsfile = sys.argv[1]
with open(xlsfile, 'rb') as f:
    reader = csv.reader(f, delimiter='\t')
    item = row[0]
    pct_change = row[3]
    # this is where I draw a blank
    # was thinking of something akin to
    #   foreach item do sum(pct_change)
    # but that's obviously wrong
    print item, sum_pct_change
f.close()

Pandas 是处理表格数据的好工具。

在这里,你会做:

import pandas as pd

data = pd.read_csv('path_to_your_file', sep='\t', header=0, decimal=',')

summed = data.groupby(by=['name'])['change_pct'].sum()

summed.to_csv('name_of_output_file', sep='\t')

需要注意的几个问题:如果列名中有白色 space,则需要清理它,或者在上面的代码中使用确切的列名(例如 ' name ' 而不是 'name').

使用defaultdict:

from collections import defaultdict

with open(xlsfile) as fobj:
    next(fobj)   # throw away first line
    res = defaultdict(float)
    for line in fobj:
        values = line.split()  #  split at whitespace
        #  use value of first column as key
        #  take value of last column  replace `,` by `.` and convert to `float`
        #  and use as value
        res[values[0]] += float(values[-1].replace(',', '.'))

print(res)

输出:

defaultdict(float,
            {'ItemA': -1.0799999999999998,
             'ItemB': 11.56,
             'ItemC': 3.8600000000000003,
             'ItemD': -4.52,
             'ItemE': 0.0})

一个pandas有效的解决方案:

import pandas as pd

with open(xlsfile) as fobj:
    header = [entry.strip() for entry in next(fobj).split(',')]

data = pd.read_csv(xlsfile, delim_whitespace=True, decimal=',', names=header, skiprows=1)
summed = data.groupby(by=['name'])['change_pct'].sum()

print(summed)

输出:

name
ItemA    -1.08
ItemB    11.56
ItemC     3.86
ItemD    -4.52
ItemE     0.00
Name: change_pct, dtype: float64

编辑

如果您的文件是 ; 分隔的。这应该有效:

data = pd.read_csv('pct2.csv', sep=';', decimal=',')
summed = data.groupby(by=['name'])['change_pct'].sum()
print(summed)

这是一种相当易读的方法,可以将读取的每一行转换为 namedtuple 以简化字段访问:

from collections import namedtuple
import csv
import sys

xlsfile = sys.argv[1]

# define field names for easy access
Record = namedtuple('Record', 'name, current_value, current_pct, change_pct')

totals = {}  # dictionary to hold totals

with open(xlsfile, 'rb') as f:
    reader = csv.reader(f, delimiter='\t')
    next(reader)  # skip over header row
    for rec in (Record._make(row) for row in reader):
        totals[rec.name] = (totals.get(rec.name, 0.0) + float(rec.change_pct))

print('name      total_change_pct')
for item in sorted(totals.items()):
    print('{:5}     {:.2f}'.format(item[0], item[1]))

输出:

name      total_change_pct
ItemA     -1.08
ItemB     11.56
ItemC     3.86
ItemD     -4.52
ItemE     0.00