#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. Ну, это, вероятно, потому, что ваши данные не выглядят так, как в примере, как вы упоминали в другом месте. Для сторонника понижающего голоса было бы оценено обоснование понижающего голоса.