Вывести значения из словаря в новый CSV-файл - PullRequest
2 голосов
/ 30 октября 2019

У меня есть CSV-файл выглядит следующим образом

year,gender,age,country
2002,F,9-10,CO
2002,F,9-10,CO
2002,M,9-10,CO
2002,F,9-10,BR
2002,M,11-15,BR
2002,F,11-15,CO
2003,F,9-10,CO
2003,M,9-10,CO
2003,F,9-10,BR
2003,M,9-10,CO
2004,F,11-15,BR
2004,F,11-15,CO
2004,F,9-10,BR
2004,F,9-10,CO

И я хочу получить выходной файл, как это:

year,gender,age,country,population
2002,F,9-10,CO,2
2002,M,9-10,CO,1
2002,F,9-10,BR,1
2002,M,9-10,BR,0
2002,F,11-15,CO,1
2002,M,11-15,CO,0
2002,F,11-15,BR,0
2002,M,11-15,BR,1
2003,F,9-10,CO,1
2003,M,9-10,CO,1
2003,F,9-10,BR,1
2003,M,9-10,BR,0
2003,F,11-15,CO,0
2003,M,11-15,CO,0
2004,F,9-10,CO,1
2004,M,9-10,CO,0
2004,F,9-10,BR,1
2004,M,9-10,BR,0
2004,F,11-15,CO,1
2004,M,11-15,CO,0
2004,F,11-15,BR,1
2004,M,11-15,BR,0

В основном я хочу распечатать число женщиндля каждого года, каждого возраста и каждой страны, таким образом, год, пол, возраст и страна будут ключом словаря. Более того, в каком-то году нет данных о конкретной стране, или в каком-то году нет определенного возраста для конкретной страны. Например, в 2003 году у женщин не было данных по 11-15 возрастным группам в стране CO. В этой ситуации численность населения будет равна 0. Более того, в некоторый год вообще нет конкретных гендерных данных. Например, за 2004 год нет данных о мужчинах для всех возрастов и стран, но я все еще хочу распечатать их в выходном файле с населением 0.

Ниже приведен код Python, который я написал, но онне работает, и я не знаю, как справиться с отсутствующими данными и распечатать их как 0 в поле населения.

import csv
import os
import sys
from operator import itemgetter, attrgetter
import math
from collections import Counter

# Create dictionary to hold the data
valDic = {}

# Read data into dictionary
with open(sys.argv[1], "r",) as inputfile:
    readcsv = csv.reader(inputfile, delimiter = ',')    
    next(readcsv)
    for line in readcsv:
        key = line[0] + line[1] + line[2] + line[3]
        year = line[0]
        gender = line[1]
        age = line[2]
        country = line[3]
        if key in valDic:
            key = key + 1
        else:
            valDic[key] = [year, gender, age, country, 0] # 0s are placeholder for running sum and itemCount
    inputfile.close()  

newcsvfile = []

for key in valDic:
    newcsvfile.append([valDic[key][0], valDic[key][1], valDic[key][2], valDic[key][3], len(valDic[key])])

newcsvfile = sorted(newcsvfile)
newcsvfile = [["year", "gender", "age", "country", "population"]] 

with open(sys.argv[2], "w") as outputfile:
    writer = csv.writer(outputfile)
    writer.writerows(newcsvfile)        

Ответы [ 2 ]

2 голосов
/ 30 октября 2019

Я бы использовал pandas для этого.

Я могу прочитать все и создать DataFrame

import pandas as pd

df = pd.read_csv(sys.argv[1])

Используя groupby Я могу группировать строки и считать их, чтобы получить population для существующих данных. Он создает список списка со столбцами в другом порядке, но позже я преобразую его в новый DataFrame, чтобы изменить порядок столбцов и отсортировать строки.

groups = df.groupby(['year', 'age', 'country', 'gender'])

data = []

for index, group in groups:
    data.append([*index, len(group)]) # create row with population

Usign .unique() Я могу получить все уникальные значения в столбцах,

unique_years     = df['year'].unique()
unique_genders   = df['gender'].unique()
unique_age       = df['age'].unique()
unique_countries = df['country'].unique()

Я использую их с itertools.product, чтобы создать все возможные комбинации года, пола, возраста, страны, чтобы проверить, какая комбинация отсутствует в данных, чтобы добавить ее с 0

Существующие комбинации я могу найти ранее groups.indices

import itertools

all_indices = groups.indices

for index in itertools.product(all_years, all_age, all_countries, all_genders):
    if index not in indices:
        data.append([*index, 0]) # add missing row

После этого у меня есть все данные, и я могу преобразовать в DataFrame, чтобы изменить порядок столбцов и отсортировать строки

# create DataFrame with new values
final_df = pd.DataFrame(data, columns=['year', 'age', 'country', 'gender',  'population'])

# change columns order
final_df = final_df[['year', 'gender', 'age', 'country', 'population']]

# sort by 
final_df = final_df.sort_values(['year', 'age', 'country', 'gender'], ascending=[True, False, False, True])

Наконец яможете сохранить его в новом csv

final_df.to_csv(sys.argv[2], index=False)

Полный рабочий пример - вместо чтения из файла я использую io.StringIO для имитации файла в памяти - так что каждый может скопировать и протестировать его без ваших полных данных.

text = '''year,gender,age,country
2002,F,9-10,CO
2002,F,9-10,CO
2002,M,9-10,CO
2002,F,9-10,BR
2002,M,11-15,BR
2002,F,11-15,CO
2003,F,9-10,CO
2003,M,9-10,CO
2003,F,9-10,BR
2003,M,9-10,CO
2004,F,11-15,BR
2004,F,11-15,CO
2004,F,9-10,BR
2004,F,9-10,CO'''

#---------------------------------------

import pandas as pd

#df = pd.read_csv(sys.argv[1])

import io
df = pd.read_csv(io.StringIO(text))

print(df)

#---------------------------------------

groups = df.groupby(['year', 'age', 'country', 'gender'])

data = []

for index, group in groups:
    data.append([*index, len(group)])

#---------------------------------------

unique_years     = df['year'].unique()
unique_genders   = df['gender'].unique()
unique_age       = df['age'].unique()
unique_countries = df['country'].unique()

#print('years    :', unique_years)
#print('genders  :', unique_genders)
#print('age      :', unique_age)
#print('countries:', unique_countries)

import itertools

all_indices = groups.indices

for index in itertools.product(all_years, all_age, all_countries, all_genders):
    if index not in indices:
        data.append([*index, 0])

#---------------------------------------

# create DataFrame with new values
final_df = pd.DataFrame(data, columns=['year', 'age', 'country', 'gender',  'population'])

# change columns order
final_df = final_df[['year', 'gender', 'age', 'country', 'population']]

# sort by 
final_df = final_df.sort_values(['year', 'age', 'country', 'gender'], ascending=[True, False, False, True])

# reset index
final_df = final_df.reset_index(drop=True)
print(final_df)

# save in file
#final_df.to_csv(sys.argv[2], index=False)
final_df.to_csv('output.csv', index=False)
2 голосов
/ 30 октября 2019

Мы можем хранить каждую комбинацию года, пола, возраста, страны как кортеж и использовать это в качестве ключа для вашего словаря. Мы также поддерживаем уникальный набор каждого из этих значений. Мы перебираем каждую комбинацию, которую видели, и если данных для этого не существует (как в 2004 году существует только женщина, но не мужчина);тогда мы можем добавить «0» для этого.

Демо:

import csv
import sys

# Create dictionary to hold the data
valDic = {}

years, genders, age, country = set(), set(), set(), set()

# Read data into dictionary
with open(sys.argv[1], 'r',) as inputfile:

    reader = csv.reader(inputfile, delimiter = ',')
    next(reader)

    for row in reader:

        key = (row[0], row[1], row[2], row[3])

        years.add(key[0])
        genders.add(key[1])
        age.add(key[2])
        country.add(key[3])

        if key not in valDic:
            valDic[key]=0

        valDic[key]+=1


#Add missing combinations
for y in years:
    for g in genders:
        for a in age:
            for c in country:
                key = (y, g, a, c)
                if key not in valDic:
                    valDic[key]=0

#Prepare new CSV
newcsvfile = [["year", "gender", "age", "country", "population"]] 

for key, val in sorted(valDic.items()):
    newcsvfile.append([key[0], key[1], key[2], key[3], valDic[key]])

with open(sys.argv[2], "w", newline='') as outputfile:
    writer = csv.writer(outputfile)
    writer.writerows(newcsvfile)  

Выходы:

year,gender,age,country,population
2002,F,11-15,BR,0
2002,F,11-15,CO,1
2002,F,9-10,BR,1
2002,F,9-10,CO,2
2002,M,11-15,BR,1
2002,M,11-15,CO,0
2002,M,9-10,BR,0
2002,M,9-10,CO,1
2003,F,11-15,BR,0
2003,F,11-15,CO,0
2003,F,9-10,BR,1
2003,F,9-10,CO,1
2003,M,11-15,BR,0
2003,M,11-15,CO,0
2003,M,9-10,BR,0
2003,M,9-10,CO,2
2004,F,11-15,BR,1
2004,F,11-15,CO,1
2004,F,9-10,BR,1
2004,F,9-10,CO,1
2004,M,11-15,BR,0
2004,M,11-15,CO,0
2004,M,9-10,BR,0
2004,M,9-10,CO,0
...