группировка связанных данных в файле csv Excel

#python #regex #grouping

#python #регулярное выражение #группировка

Вопрос:

это файл csv Excel

    Receipt Name    Address      Date       Time    Total
    25007   A      ABC pte ltd   3/7/2016   10:40   12.30
    25008   A      ABC ptd ltd   3/7/2016   11.30   6.70
    25009   B      CCC ptd ltd   4/7/2016   07.35   23.40
    25010   A      ABC pte ltd   4/7/2016   12:40   9.90
  

как мне получить даты и время и сгруппировать их соответственно для компаний A и B, чтобы результат был примерно таким: (A, 3/7/2016, 10:40, 11.30, 4/7/2016 12:40), ( B, 07.04.2016, 07:35)

Мой существующий код:

 datePattern = re.compile(r"(d /d /d )s (d :d )")  
dateDict =dict()    

for i, line in enumerate(open('sample_data.csv')):
    for match in re.finditer(datePattern,line):
        if match.group(1) in dateDict:
            dateDict[match.group(1)].append(match.group(2))
        else:
            dateDict[match.group(1)] = [match.group(2),]
  

Однако это работает только для группировки даты и времени, но теперь я хочу включить имя как часть группировки. * Предпочтительнее использовать модуль csv

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

1. Если я правильно понял, вам нужен словарь от названия компании до метки времени (дата время). В этом случае вы хотите, чтобы названия компаний использовались в качестве ключей словаря. Это правильно?

2. да, это верно. название компании, которое является ключом словаря, должно содержать дату и время в качестве своего значения

3. Почему вы используете регулярное выражение?

4. у вас есть идеи получше? это лучшее, что я могу придумать… хотелось бы попробовать csv-модули

5. Мой ответ на ваш предыдущий вопрос показывает вам, как прочитать файл с помощью библиотеки csv, после чего группировка становится тривиальной с defaultdict

Ответ №1:

Предполагая, что ваши данные на самом деле выглядят так:

 Receipt,Name,Address,Date,Time,Items
25007,A,ABC pte ltd,4/7/2016,10:40,"Cheese, Cookie, Pie"
25008,A,CCC pte ltd,4/7/2016,11:30,"Cheese, Cookie"
25009,B,CCC pte ltd,4/7/2016,07:35,"Chocolate"
25010,A,CCC pte ltd,4/7/2016,12:40," Butter, Cookie"
  

тогда группировать довольно просто:

 from collections import defaultdict
from csv import reader
with open("test.csv") as f:
    next(f) # skip header
    group_dict = defaultdict(list)
    for _, name, _, dte, time, _ in reader(f):
        group_dict[name].append((dte, time))

from  pprint import pprint as pp

pp(dict(group_dict))
  

что даст вам:

 'A': [('4/7/2016', '10:40'), ('4/7/2016', '11:30'), ('4/7/2016', '12:40')],
 'B': [('4/7/2016', '07:35')]}
  

Если вы не хотите, чтобы дата повторялась, то также группируйте по этому:

 with open("test.csv") as f:
    next(f) # skip header
    group_dict = defaultdict(list)
    for _, name, _, dte, time, _ in reader(f):
        group_dict[name, dte].append(time)

from  pprint import pprint as pp

pp(dict(group_dict))
  

Что даст вам:

 {('A', '4/7/2016'): ['10:40', '11:30', '12:40'], ('B', '4/7/2016'): ['07:35']}
  

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

1. ошибка ValueError: слишком много значений для распаковки. я полагаю, что что-то не так с «для _, name, _, dte, time, _ в reader (f):»?

2. Разместите данные точно так, как вы их видите в своем файле, это определенно не так, как у вас в вашем вопросе

3. извините за это, у меня это получилось, потому что в моем исходном файле есть еще несколько полей, которые я не включил в образец здесь. Еще одна проблема заключается в том, как мне исключить заголовок, потому что он печатает «квитанцию», «имя» и т. Д

4. Сработало ли мое последнее решение для вашего предыдущего вопроса?

5. Это правильный вывод no? Или вы просто группируете по дате и имени?

Ответ №2:

Это можно сделать довольно легко с помощью модуля Pandas:

 import pandas as pd

df = pd.read_csv('/path/to/file.csv')

df.groupby(['Name','Date']).Time.apply(list).reset_index().to_csv('d:/temp/out.csv', index=False)
  

D:tempout.csv:

 Name,Date,Time
A,3/7/2016,"['10:40', '11.30']"
A,4/7/2016,['12:40']
B,4/7/2016,['07.35']
  

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

1. Должен ли я устанавливать что-либо, в котором говорится, что модуль panda не найден.. есть ли альтернативный способ сделать это?

2. @DarrylDan, да, модуль Pandas должен быть установлен дополнительно… И да, существует довольно много альтернативных методов

Ответ №3:

Если вы не хотите использовать Pandas, это возможное решение. Это не самый элегантный способ, поскольку ваш формат csv относительно неудобен для анализа. Если вы можете изменить формат, чтобы использовать разделитель полей, не содержащий пробелов, предпочтительнее использовать соответствующую библиотеку синтаксического анализа csv (например, pandas встроенный csv модуль или Python).

 import re

datePattern = re.compile(r"(d /d /d )s (d [:.]d )")
companyPattern = re.compile(r"^s d s (w )")
companyDict = {}

for i, line in enumerate(open('sample_data.csv')):
    # skip csv header
    if i == 0:
        continue

    timestampMatch = datePattern.search(line)
    companyMatch   = companyPattern.search(line)

    # filter out any malformed lines which don't match
    if timestampMatch is None or companyMatch is None:
        continue

    date = timestampMatch.group(1)
    time = timestampMatch.group(2)
    company = companyMatch.group(1)

    companyDict.setdefault(company, []).append("{} {}".format(date, time))
  

Обратите внимание, что поле времени не согласуется с тем, использует ли оно . или : для разделителя часов / минут, поэтому я принял это во внимание.

Выполнение этого для ваших выборочных данных приводит к следующему значению для companyDict :

 {'A': ['3/7/2016 10:40', '3/7/2016 11.30', '4/7/2016 12:40'], 'B': ['4/7/2016 07.35']} 
  

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

1. это странно, он ничего не выводит, когда я делаю «печать companyDict»

2. Ну, это, вероятно, потому, что ваши данные не выглядят так, как в примере, как вы упоминали в другом месте. Для сторонника понижающего голоса было бы оценено обоснование понижающего голоса.