Группировать по и среднему значению без pandas в файле Csv

#python

#python

Вопрос:

Имейте в виду, что я новичок в Python — у меня есть список со странами и населением в каждой области в файле csv.. выглядит так

 ['country', 'population']
['Usa', '1273']
['Usa', '4343']
['Usa', '1240']
['Uk', '7879']
['Uk', '3224']
['Uk', '4342']
['Tr', '6565']
['Tr', '7889']
['Tr', '1980']
  

Из этого списка мне нужно распечатать следующие данные (без использования pandas)

 ['country', 'avgPop']
['Usa', '2285']
['Uk', '5148']
['Tr', '5478']
  

до сих пор у меня есть отсортированный список, но я понятия не имею, как решить мою проблему.. помочь?

 import csv
import requests
import operator

with requests.Session() as s:
download = s.get(CSV_URL)

decoded_content = download.content.decode('utf-8')

cr = csv.reader(decoded_content.splitlines(), delimiter=',')
my_list = list(cr)
sortedlist = sorted(my_list, key=operator.itemgetter(1), reverse=True)

with open ("openSomeNewFileDest.csv", 'w' , newline='') as f:
thewriter = csv.writer(f)
for row in sortedlist:
    my_row = []
    my_row.append(row[1])
    my_row.append(row[9])
    print(my_row)
  

Комментарии:

1. Как бы вы подошли к этой проблеме, если бы вам нужно было сделать это самостоятельно, вручную, на бумаге? Запишите это, а затем обобщите в коде.

2. (ping) Не могли бы вы, пожалуйста, помочь механике stackoverflow, приняв ответ, который вам понравился больше всего (если он действительно есть), чтобы авторы ответов не видели этот вопрос в своем активном списке 😉 спасибо за участие. Если ни один из ответов не был релевантным, пожалуйста, проигнорируйте этот пинг.

Ответ №1:

Будет ли что-то подобное работать для вас? data Содержит список, который вы только что отсортировали.

 data = [['country', 'population'],
['Usa', '1273'],
['Usa', '4343'],
['Usa', '1240'],
['Uk', '7879'],
['Uk', '3224'],
['Uk', '4342'],
['Tr', '6565'],
['Tr', '7889'],
['Tr', '1980']]

temp = {}

for i in range(1, len(data)):
    if data[i][0] not in temp.keys():
        temp[data[i][0]] = {
                "sum": int(data[i][1]),
                "count": 1
                }
    else:
        temp[data[i][0]]["sum"]  = int(data[i][1])
        temp[data[i][0]]["count"]  = 1

out = [["country", "avgPop"]]

for key in temp.keys():
    avg = int(temp[key]["sum"] / temp[key]["count"])
    out.append([key, avg])

print(out)
  

Вывод:

 [['country', 'avgPop'], 
 ['Usa', 2285], 
 ['Uk', 5148], 
 ['Tr', 5478]]
  

Комментарии:

1. Это идеально, я использовал его …. но заметил, что он удаляет элемент из массива, поэтому я изменил его на: for i in range(0, len(data)): тогда это сработало. Также обратите внимание, что я также удалил заголовки для своих.

2. @Steve237 Рад, что смог помочь! Мое решение использует range(1, len(data)) , потому что оно предполагает, что данные содержат заголовки.

Ответ №2:

Я полагаю, это делает именно то, о чем вы просили:

 import csv

index = {}
with open('/tmp/data.csv') as f:
    cr = csv.reader(f)
    next(cr) # skip header row
    for row in cr:
        index.setdefault(row[0], []).append(int(row[1]))

print("['country', 'avgPop']")
for c, v in index.items():
    print("['{}', '{}']".format(c, int(sum(v) / len(v))))
  

Входной файл CSV:

 country, population
Usa, 1273
Usa, 4343
Usa, 1240
Uk, 7879
Uk, 3224
Uk, 4342
Tr, 6565
Tr, 7889
Tr, 1980
  

Результат:

 ['country', 'avgPop']
['Usa', '2285']
['Uk', '5148']
['Tr', '5478']
  

Комментарии:

1. Спасибо за вашу помощь!! что, если я хочу вывести данные из более чем 2 столбцов? есть ли какой-нибудь способ сделать это с помощью setDeafault или мне нужно заменить его каким-либо другим вариантом?

2. Вы можете делать все, что хотите — setDefault — это как раз то, что нужно для того, что вы хотели сделать в первую очередь. Вам нужно определить, какой новый результат вы хотите, и только тогда вы можете подумать о том, как вы собираетесь получить этот результат. — каким будет следующий столбец?

Ответ №3:

Вот как это делается идиоматически (отсюда лучшая читаемость, наименьшее количество ошибок и лучшая производительность процессора / памяти) с помощью базовых инструментов:

 from itertools import groupby

def get_avg(vs):
    sum_vs = 0
    num_vs = 0
    for v in vs:
        sum_vs  = v
        num_vs  = 1
    return sum_vs / num_vs

def group_by(rows, key):
    return groupby(sorted(rows, key=key), key=key)

rows = csv.reader(decoded_content.splitlines(), delimiter=',')

for country, rows in group_by(rows, lambda row: row[0]):
    print(country, get_avg(float(row[1]) for row in rows))
  

Вы используете sorted и itertools.groupby с тем же лямбда, что удобно дает вам сгруппированные строки.