如何在 Python 中聚合 CSV 文件中的列值
How to aggregate column values from a CSV file in Python
我在 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
,我想为每个特定 time
的特定状态添加所有 amount
。例如,在上面的示例中,companyid
1 有两条记录用于 time
2012Q1
- 一条用于 AK_995
,一条用于 AK_996
。我想在这两个中添加 amount 并且将 AK 设置为 location
,以获得一个值为 2012Q1,AK,1,13484260.129
的记录。对于所有州,每个 time
周期的每个 company
都应该这样做。请注意,不应添加跨 time
的 amounts
,因为在上面的样本 companyid
3
中有 2 个相同状态但在不同 time
期间的记录。此外,我只想在 Metrics
为 Sales
的情况下执行此操作,因此我想删除 Metrics
不同于 Sales
的任何行,并且不要在聚合中添加这些数量。
我还想将输出写入另一个 csv 文件。我怎样才能做到这一点?
更新部分:
根据 @MichaelLaszlo 的建议,我有这段代码。代码似乎有一个问题。我在输出文件中想要的是将特定 companyid
的所有记录放在一起。 companyid
中记录的顺序应该是 time
每 location
的递增顺序(特定位置的记录针对特定 companyid
聚集在一起)。例如,如果有 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
的记录是分散的,我希望按照我在更新部分中提到的顺序输出。
我不知道你的数据集的大小,但你应该开始考虑使用 pandas。
您将受益于许多工具,例如从 csv 到按列分组的数据框创建。
最后,您可以灵活选择输出,而且速度非常快。
编辑:
抱歉,我现在只有 phone,但这是从 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
它看起来像:
import pandas as pd
df = pd.DataFrame.from_csv(r'yourPathToCsv.csv')
data_grouped = df.groupby(['col1','col2'])['colAmount'].sum().to_frame()
然后您可以使用 to_csv() 函数从 Dataframe 中导出数据。
更新:现在 read_csv
方法优于 from_csv
方法。这是一个更新的示例:
import pandas as pd
df = pd.read_csv(r'yourPathToCsv.csv')
data_grouped = df.groupby(['col1','col2'])['colAmount'].sum().to_frame()
不确定,这是否是您要查找的内容,但是您可以使用字典来收集您感兴趣的键下的值,有点像这样:
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 数据的位置 table。
简单但不适合海量数据:
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))
要聚合数据,请使用散列。从要聚合的值的元组中创建键。
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
.
编辑:添加了对空行的处理
首先将数据读取到 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'
)
我在 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
,我想为每个特定 time
的特定状态添加所有 amount
。例如,在上面的示例中,companyid
1 有两条记录用于 time
2012Q1
- 一条用于 AK_995
,一条用于 AK_996
。我想在这两个中添加 amount 并且将 AK 设置为 location
,以获得一个值为 2012Q1,AK,1,13484260.129
的记录。对于所有州,每个 time
周期的每个 company
都应该这样做。请注意,不应添加跨 time
的 amounts
,因为在上面的样本 companyid
3
中有 2 个相同状态但在不同 time
期间的记录。此外,我只想在 Metrics
为 Sales
的情况下执行此操作,因此我想删除 Metrics
不同于 Sales
的任何行,并且不要在聚合中添加这些数量。
我还想将输出写入另一个 csv 文件。我怎样才能做到这一点?
更新部分:
根据 @MichaelLaszlo 的建议,我有这段代码。代码似乎有一个问题。我在输出文件中想要的是将特定 companyid
的所有记录放在一起。 companyid
中记录的顺序应该是 time
每 location
的递增顺序(特定位置的记录针对特定 companyid
聚集在一起)。例如,如果有 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
的记录是分散的,我希望按照我在更新部分中提到的顺序输出。
我不知道你的数据集的大小,但你应该开始考虑使用 pandas。 您将受益于许多工具,例如从 csv 到按列分组的数据框创建。 最后,您可以灵活选择输出,而且速度非常快。
编辑: 抱歉,我现在只有 phone,但这是从 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 它看起来像:
import pandas as pd
df = pd.DataFrame.from_csv(r'yourPathToCsv.csv')
data_grouped = df.groupby(['col1','col2'])['colAmount'].sum().to_frame()
然后您可以使用 to_csv() 函数从 Dataframe 中导出数据。
更新:现在 read_csv
方法优于 from_csv
方法。这是一个更新的示例:
import pandas as pd
df = pd.read_csv(r'yourPathToCsv.csv')
data_grouped = df.groupby(['col1','col2'])['colAmount'].sum().to_frame()
不确定,这是否是您要查找的内容,但是您可以使用字典来收集您感兴趣的键下的值,有点像这样:
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 数据的位置 table。
简单但不适合海量数据:
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))
要聚合数据,请使用散列。从要聚合的值的元组中创建键。
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
.
编辑:添加了对空行的处理
首先将数据读取到 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'
)