如何在Python

时间:2015-09-04 21:51:23

标签: python csv aggregation

我在CSV文件中有一个数据集。这是一个示例:

Time,Location,Companyid,Metrics,Amount

2012Q1,AK_995,A,Sales,8820156.363
2012Q1,AK_995,B,Revenue,28392730.51
2012Q1,AK_995,C,Sales,6980332.166
2012Q1,AK_996,B,Revenue,1894254.13
2012Q1,AK_996,A,Sales,4664103.766
2012Q2,AK_995,C,Sales,7980332.166

此处time是年份和季度,location是带有ID的状态符号,因此每个州可能有多个行,每个companyid具有不同的ID。我想要做的是,对于每个companyid我想为每个特定amount的特定状态添加所有time。例如,在上面的示例中,companyid 1有time 2012Q1的两条记录 - 一条用于AK_995,另一条用于AK_996。我想在这两个中添加金额,并将AK作为location,以获得一条值为2012Q1,AK,1,13484260.129的记录。对于所有州,每个company每个time期间应该这样做。请注意,不应添加amounts time companyid,因为上面的示例3 time有2条相同状态的记录但在Metrics期间不同。另外,我只想在SalesMetrics的情况下执行此操作,因此我想删除Sales不是companyid的任何行,并且也不要在聚合中添加这些数量。< / p>

我还想将输出写入另一个csv文件。我怎样才能做到这一点?

更新部分:

根据 @MichaelLaszlo 的建议,我有这段代码。代码似乎有一个问题。我想要的输出文件是让特定companyid的所有记录聚集在一起。 time内的记录顺序应按照locationcompanyid个增加的顺序排列(某个特定位置的记录汇集到一个特定的companyid)。例如,如果有B companyid,则B companyid,state,time,amount B,AK,2010Q1,5000 B,AK,2010Q2,5100 B,AK,2010Q3,4300 B,AK,2010Q4,4350 B,AK,2011Q1,5600 的所有记录应该在一起,订单应如下所示:

companyid

正如您在上面所看到的,B companyid的所有记录都在一起,B location内的特定time记录在一起companyids。在我当前的输出中,我得到所有totals = {} # Aggregate sales by quarter, state, and company. for row in csv.reader(open('data.csv')): if row[3] == 'Sales': key = (row[0], row[1][:2], row[2]) totals[key] = totals.setdefault(key, 0) + float(row[4]) # Write aggregated data to file. with open('aggregated.csv', 'w') as out_file: writer = csv.writer(out_file) for key, value in totals.items(): row = list(key) + [value] writer.writerow(row) 分散的记录。我目前的代码是:

time,state,companyid,amount
2014Q4,AL_,B,547991592.5101689
2014Q1,NV_,B,387534045.40654004
2012Q3,SC_,A,333657617.05835015
2014Q4,DC_,C,54022786.60577
2014Q3,TN_,B,594121931.7221502

我目前的样本输出是:

companyid

正如您所看到的,B $sql = "SELECT area, (ROUND(AVG(age))) as avrage FROM mydb GROUP BY area"; $result = mysqli_query($con,$sql); while(list($area, $avrage) = mysqli_fetch_row($result)) { *** HAD TO <SNIP> OUT THIS HTML/EMBEDDED PHP CODE FOR DISPLAYING OUTPUT } 的记录已经分散,我希望按照我在更新部分中提到的顺序输出。

5 个答案:

答案 0 :(得分:3)

要聚合数据,请使用哈希。从要聚合的值的元组创建键。

totals = {}

for row in csv.reader(open('data.csv')):
  if row[3] == 'Sales':
    key = (row[2], row[1][:2], row[0])
    totals[key] = totals.setdefault(key, 0) + float(row[4])

要写入CSV文件,请在打开的文件对象上使用csv.writer()。要创建行,请将每个哈希键转换为列表并将其与总销售额连接起来。

import csv

with open('aggregated.csv', 'w') as out_file:
  writer = csv.writer(out_file)
  for key, value in sorted(totals.items()):
    row = list(key) + [value]
    writer.writerow(row)

我们可以将这两个操作放在一个简短的脚本中:

import csv

totals = {}

# Aggregate sales by company, state, and quarter.
for row in csv.reader(open('data.csv')):
  if row[3] == 'Sales':
    key = (row[2], row[1][:2], row[0])
    totals[key] = totals.setdefault(key, 0) + float(row[4])

# Write aggregated data to file.
with open('aggregated.csv', 'w') as out_file:
  writer = csv.writer(out_file)
  for key, value in sorted(totals.items()):
    row = list(key) + [value]
    writer.writerow(row)

运行上面的脚本并检查生成的文件aggregated.csv

答案 1 :(得分:2)

我不知道您的数据集的大小,但您应该开始考虑使用pandas。 您将受益于许多工具,例如从csv到按列分组创建数据框。 最后,您可以灵活地选择输出,而且速度非常快。

编辑: 抱歉,我现在只有手机,但这里是如何从csv生成数据帧:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.from_csv.html 这是groupby:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html 它看起来像是:

read_csv

然后,您可以使用Dataframe中的to_csv()函数导出数据。

更新from_csv方法现在优先于import pandas as pd df = pd.read_csv(r'yourPathToCsv.csv') data_grouped = df.groupby(['col1','col2'])['colAmount'].sum().to_frame() 方法。这是一个更新的例子:

{{1}}

答案 2 :(得分:1)

简单但不适用于巨大数据:

import csv

source = {}
with open('filename.csv', 'rb') as csvfile:
    csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')
    next(csvreader , None) #  skip line
    next(csvreader , None) #  skip line
    for row in csvreader:
        if row[3] != 'Sales':
            continue
        data_date = row[0]
        data_state = row[1].split('_')[0]
        data_company = row[2]
        data_amount = float(row[4])
        if data_date not in source:
            source[data_date] = {}
        if data_state not in source[data_date]:
            source[data_date][data_state] = {}
        if data_company not in source[data_date][data_state]:
            source[data_date][data_state][data_company] = []
        source[data_date][data_state][data_company].append(data_amount)

    for k_date in source:
        for k_state in source[k_date]:
            for k_company in source[k_date][k_state]:
                data = source[k_date][k_state][k_company]
                average = ( sum(data) / len(data) )
                print('%s,%s,%s,%s' % (k_date, k_state, k_company, average))

答案 3 :(得分:1)

编辑:添加了对空行的处理

首先将您的数据读取到pandas数据帧:

import pandas as pd
data = pd.read_csv('data.csv')

删除空行:

data.dropna(how="all", inplace=True) 

重命名位置列:

data['Location'] = data['Location'].apply(
    lambda location: location.split('_')[0]
)

然后进行处理并保存到文件:

data[data['Metrics']=='Sales'].groupby(
    ['Time','Location','Companyid']
).sum().to_csv(
    'results.csv'
)

答案 4 :(得分:0)

不确定,这是你想要的,但你可以使用dict,收集你感兴趣的键下的值,有点像这样:

agg = {}

for row in dat:
  if row[3] == 'Sales':
    state = row[1][:1]
    old = agg.get((row[0], state, row[2]), 0.0)
    agg[(row[0],state,row[2])] = old + row[4]

其中dat保存csv表中的数据。