Страницы

Поиск по вопросам

пятница, 28 февраля 2020 г.

Связать два CSV файла по столбцу (с агрегацией)

#python #csv


Суть данного скрипта в том, чтобы он вывел список значений из 2 файла, соответствующих
значению id из первого файла. В итоге он выводит список лишь для самого первого id,
а для остальных выдает пустой список "[ ]". Причем для каждого из этих id есть соответствующие
значения, пустых списков там выводиться не должно. Что я не так делаю?

posts_table = open("posts.csv")
cat_rel_table = open("category_relationship.csv")

reader_1 = csv.DictReader(posts_table)
reader_2 = csv.DictReader(cat_rel_table)

def cat_name(post_id):
    cat_list = []
    for cat in reader_2:
        if cat['post_id'] == post_id:
            cat_list.append(cat['cat_id'])
    return cat_list

for post in reader_1:
    if (post['type'] == "8" and post['status'] == "1"):
        print(post['id'], cat_name(post['id']))


вот пример содержимого posts.csv:

"id","type","price","new_price","from_date","to_date","parent","created_at","author","featured","template","stock","view","status","barcode"
"84","8","117","0","0000-00-00 00:00:00","0000-00-00 00:00:00","0","2017-10-12 14:37:38","1","../uploads/posts/2017/10/1-10-r-c-audi-r8-v10-compl-6v.jpg","0","10","0","2",
"85","8","28","0","0000-00-00 00:00:00","0000-00-00 00:00:00","266","2017-10-12 17:41:45","1","../uploads/posts/2017/10/0011543346227-a.jpg","0","10","0","2",
"86","8","13","0","0000-00-00 00:00:00","0000-00-00 00:00:00","266","2017-10-19 10:38:06","1","../uploads/posts/2017/10/81XHlhvCsJL._SL1500_.jpg","0","10","0","2",
"87","8","28","0","0000-00-00 00:00:00","0000-00-00 00:00:00","266","2017-10-19 11:03:55","4","../uploads/posts/2017/10/cat-9-inch-big-builder-l&s-shaking-machine-vehicle-dump-truck--5AE442DA.zoom.jpg","0","10","0","1","11543346210"
"88","8","28","0","0000-00-00 00:00:00","0000-00-00 00:00:00","0","2017-10-19 11:05:59","1","../uploads/posts/2017/10/pTRUCA1-22577036_alternate1_enh-z6.jpg","0","10","0","2",


Пример category_relationship.csv

"id","type","cat_id","post_id","status"
"31","8","21","84","2"
"32","8","21","85","2"
"33","8","20","86","2"
"34","8","21","86","2"
"35","8","20","87","1"
"36","8","21","87","2"
"37","8","20","88","2"
"38","8","21","88","2"


Ожидаемый вывод: {131: ['2', '11', '43', '45', '72', '5', '8', '44']} (для каждого
айдишника). Т.е. слева айдишник из первой таблицы, а справа список значений который
скрипт получает из другой таблицы.
    


Ответы

Ответ 1



Вот теперь разобрался. У Вас, проблема в том, что конструкции open("category_relationship.csv") и csv.DictReader выдают объекты типа итератора, и после первого прохода курсор остается в конце, соответственно значений он более не возвращает, отсюда и пустой вывод при каждом следующем проходе. Для того, чтобы этого избежать, нужно считывать данные из файла для каждого прохода. Получается вот так: import csv posts = csv.DictReader(open("posts.csv")) def cat_list(post_id): return [item['cat_id'] for item in csv.DictReader(open("category_relationship.csv")) if item['post_id'] == post_id] di = {post['id']: cat_list(post['id']) for post in posts if post['type'] == "8" and post['status'] == "1"} # теперь словарь di можно использовать по своему усмотрению print(di) for key, val in di.items(): print(key, val) Решение на основе предложения топикстртера: import csv cat_file = open("category_relationship.csv") category = csv.DictReader(cat_file) posts = csv.DictReader(open("posts.csv")) # Поскольку здесь только один проход, скомбинируем. def cat_list(post_id): cat_file.seek(0) # Возвращаем курсор в начальное положение. return [item['cat_id'] for item in category if item['post_id'] == post_id] di = {post['id']: cat_list(post['id']) for post in posts if post['type'] == "8" and post['status'] == "1"} # теперь словарь можно использовать по своему усмотрению print(di) for key, val in di.items(): print(key, val)

Ответ 2



Для подобных задач идеально подходит модуль Pandas: import pandas as pd # pip install pandas p = pd.read_csv(r'D:\temp\posts.csv') c = pd.read_csv(r'D:\temp\category_relationship.csv') res = (p.loc[(p['type']==8) & (p['status']==1), ['id']] .set_index('id') .join(c.groupby('post_id')['cat_id'] .apply(lambda x: x.values.tolist()))) результат: In [372]: p Out[372]: id type price new_price from_date ... template stock view status barcode 0 84 8 117 0 0000-00-00 00:00:00 ... 0 10 0 2 NaN 1 85 8 28 0 0000-00-00 00:00:00 ... 0 10 0 1 NaN 2 86 8 13 0 0000-00-00 00:00:00 ... 0 10 0 2 NaN 3 87 8 28 0 0000-00-00 00:00:00 ... 0 10 0 1 1.154335e+10 4 88 8 28 0 0000-00-00 00:00:00 ... 0 10 0 2 NaN [5 rows x 15 columns] In [373]: c Out[373]: id type cat_id post_id status 0 31 8 21 84 2 1 32 8 21 85 2 2 33 8 20 86 2 3 34 8 21 86 2 4 35 8 20 87 1 5 36 8 21 87 2 6 37 8 20 88 2 7 38 8 21 88 2 In [374]: res Out[374]: cat_id id 85 [21] 87 [20, 21] In [375]: res.to_dict()['cat_id'] Out[375]: {85: [21], 87: [20, 21]}

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

Отправить комментарий