2014-04-10 1 views
1

각 행에 대해 이전 10 개 날짜의 값을 그룹화하려고합니다. 날짜, 항목, 판매, 파트너 등의 열이있는 .csv 파일이 있습니다. 날짜, 항목, 합계 (판매) (특정 항목의 판매로 지난 10 일)의 결과가 필요합니다. 항목이 그룹화됩니다. 날짜는 순차적이지 않습니다 (일부 날짜에는 판매가 전혀 없으므로 날짜에서 10 일을 감할 수 없습니다). 예를 들어,
Python - 각 행의 최근 10 개 날짜의 값 그룹화

 
Date   ItemType Sales  Partner 
2014/01/01  A   $100   P2 
2014/01/01  B   $60   P1 
2014/01/04  A   $70   P2 
2014/01/06  B   $80   P2 
2014/01/08  A   $40   P3 
2014/01/09  B   $20   P2 
... 

위의 데이터 세트를 위해, 나는 다음과 같은 결과를 얻을해야합니다

 
Date   Item  Sales (in the last 10 dates) 
2014/01/04  A   $170 
2014/01/08  A   $210 

내가 파일의 각 행에 대해이 작업을 자동으로 생성해야합니다. 또한
, 나는뿐만 아니라 지난 10 날짜를 (단지 4 파트너가) 각 파트너의 수를 얻을 필요가 : 후자의 경우

 
Date    Item  P1  P2  P3 P4 
2014/01/08  A   0  2  1  0 

, 아마 전치 다음 그룹에 필요합니다. 나는이 그룹핑을하기 위해 팬더 및/또는 num.py 모듈을 사용해야 할 것 같지만 파이썬을 처음 접했고 예제를 찾을 수 없었다.

답변

1

팬더 또는 numpy와 같이 복잡한 것은 필요하지 않습니다. 이것은 매우 간단한 흐름으로 말하면, csv module입니다.

당신이 뭔가를 할 수 있습니다 :

  • 는 CSV 판독기를 사용에서 파일을 읽고, 당신은

    [['2014/01/01', 'A', '$100', 'P2'], ['2014/01/01', 'B', '$60', 'P1'], ]

  • 정렬과 같은 데이터를 데이터 그래서 keyed on the date

  • itertools.groupby을 사용하여 날짜별로 그룹화하세요.

  • 사용 slice notation (print([1,2,3,4][:2]))이 돌아와, 10 날짜를

  • 디스플레이를 잡아 또는 CSV 모듈

당신이 그 단계의 문제가있는 경우를 사용하여 새 파일에 기록하고, 새로운 질문을 게시하십시오!

+0

도움 주셔서 감사합니다. 나는 어떻게 (print ([1,2,3,4] [: 2])) 지난 10 날짜를 잡고 이해가 안 돼요. – user3519466

+0

이것은 슬라이스 표기법의 예입니다. 사용 사례에 맞게 수정해야합니다. [이 질문] (http://stackoverflow.com/q/509211/344286)에서 알아야 할 모든 내용을 설명해야합니다. –

0

목록에서 csv를 읽고 l [0]이 날짜 필드라고 가정합니다.

from itertools import groupby 

# read csv file in this list 
csv_list = [ 
    ['2014/01/01', '100'], 
    ['2014/01/01', '200'], 
    ['2014/01/04', '70'], 
    ['2014/01/08', '40'] 
] 

# make sure the list is sorted by the date in order for grouping to work ok 
csv_list.sort(key=lambda i: i[0]) 
result = [(date, sum(values[1])) for date, values in groupby(csv_list, key=lambda i: i[0])] 

result이 (그 날의 날짜, sum_of_sales)와 튜플의 목록을 포함한다 :이 방법을 itertools 사용할 수 있습니다.

이것은 그룹핑의 일부입니다. 실제 datetime 개체의 날짜를 구문 분석하여 특정 순서로 값을 인쇄 할 수 있도록 비교하려면 strptime을 사용하십시오.

0

나는 귀하의 질문을 이해한다고 생각합니다. 이 솔루션은 날짜를 가져 와서 그 날짜 이전에 마지막 N 개의 판매 합계를 찾습니다.그것을 살펴 유무 :

>>> sum_sales() 
2014-04-10 A 210 
2014-04-10 A 0 2 1 0 
2014-04-10 B 160 
2014-04-10 B 1 4 1 0 
>>> sum_sales(datetime(year=2014, month=1, day=4)) 
2014-01-04 A 170 
2014-01-04 A 0 2 0 0 
2014-01-04 B 60 
2014-01-04 B 1 2 0 0 
>>> sum_sales(datetime(year=2014, month=1, day=8), items=['A']) 
2014-01-08 A 210 
2014-01-08 A 0 2 1 0 

당신은 새로운 CSV 파일에 결과를 직접 할 수 있습니다 : 샘플 입력이 my_data.csv에 저장됩니다

import csv 
from itertools import groupby, islice, ifilter 
from datetime import datetime 


def sum_sales(date=None, filename='my_data.csv', n_days=10, items=None): 
    if date is None: 
     date = datetime.today() 

    with open(filename) as ifile: 
     reader = csv.reader(ifile, skipinitialspace=True, delimiter=' ') 
     # Skip the header 
     next(reader) 

     # Convenience functions to use later on 
     item_date = lambda row: (row[1], datetime.strptime(row[0], '%Y/%m/%d')) 

     if items is None: 
      filter_by = lambda row: datetime.strptime(row[0], '%Y/%m/%d') <= date 
     else: 
      filter_by = lambda row: datetime.strptime(row[0], '%Y/%m/%d') <= date \ 
       and row[1] in items 

     # Loop over groups of data, sorted by ItemType and data, grouped by 
     # ItemType and filtered by filter_by 
     for item, group in groupby(sorted(ifilter(
       filter_by, reader), key=item_date), lambda row: row[1]): 
      partners = {'P1': 0, 'P2': 0, 'P3': 0, 'P4': 0} 
      data = islice(group, n_days) 
      sales = 0 
      for row in data: 
       sales += int(row[2].replace('$', '')) 
       partners[row[3]] += 1 
      print '{}\t{}\t{}'.format(date.date(), item, sales) 
      print '{}\t{}\t{P1}\t{P2}\t{P3}\t{P4}'.format(date.date(), item, 
                  **partners) 

을 감안할를이 출력 될 것이다 ,하지만 그것은 당신에게 문제가되어서는 안됩니다.

+0

도움 주셔서 감사합니다. 나는 그것을 시도했다. 그러나 오늘 (첫 번째 칼럼의 날짜가 아닌) 그룹화 된 행의 형태로 약간 다른 결과를 얻는다. 날짜와 항목, 각 판매/파트너 증분에 대한 합계가있는 10 개의 행. – user3519466

+0

입력 파일, 스크립트 실행 출력 및 예상 출력을 [pastebin.com] (http://www.pastebin.com)의 세 가지 개별 붙여 넣기로 업로드 하시겠습니까? –

+0

코드 http://pastebin.com/ZBxVGwzq (파트너 수만 해당) – user3519466

0

파이썬을 처음 접했을 때 필자는 파이썬을 배울 수있는 타사 유틸리티를 포함하지 않는 솔루션을 만들었습니다. 여기에는 먼저 테이블 항목을 문자열 및 숫자 유형 항목 사전 목록으로 그룹화하는 과정이 포함됩니다. 나는 당신에게 파일을 읽게 남겨 둘 것입니다.

주 파일의 빈 항목은 다음과 같습니다.

entries = [ {"Date":"", "ItemType":"", "Sales":int(), "Partner":""}, ... ] 

나는 당신이 필요로하는 것을 정확하게하기 위해 3 가지 기능을 만들었습니다.

  • filter_entries(entries, filter_key) 가 키의 사전 반환 항목을 기반 엔트리 목록 항목 여기서 엔트리리스트 [filter_key] 값은 동일
  • expand_entries(entries, expand_key)에서, 으로 엔트리리스트를 반환 모두 초급 리스트 [expand_key]을 제거하고 모든 고유 키로 대체 다음 expand_key
  • merge_entries(entries, merge_key)에 기초한 값 쌍은 항목 기반으로 엔트리리스트를 반환 여기서 동일한 항목 [merge_key] 값이 결합되어 모든 항목
,451,515,

:

def filter_entries(entries, filter_key): 
    unique_values = set([e[expand_key] for e in entries]) 
    filtered_entries = {} 
    for filter_value in unique_values: 
     filtered_entries [filter_value] = [e for e in in entries if e[filter_key] == filter_value] 
    return filtered_entries 

def expand_entries(entries, expand_key): 
    unique_values = set([e[expand_key] for e in entries]) 
    new_entries = [] 
    for entry in entries: 
     new_entries.append({key:value for key,value in entries.items() if not key == expand_key}) 
     for new_key in unique_values: 
      new_entries[-1][new_key] = 1 if entry[expand_key] == new_key else 0 
    return new_entries 

항목을 병합하려면, 내가 그 문자열 키 - 값을 주장하는 것 같은 문자열이어야합니다. 그렇지 않으면 오류입니다. 즉, 합병 적절한 값는 다음과 같다 :

2014/01/01  A   100   
2014/01/01  A   60 
---------------------------------  
2014/01/01  A   160 

와 나쁜 경우는 다음과 같습니다

def merge_entries(entries, merge_key): 
    unique_keys = set([e[merge_key] for e in entries]) 
    new_entries = [] 
    for key in unique_keys: 
     new_entry = None 
     for entry in [e for e in entries if e[merge_key] == key]: 
      # copy the style of the first entry with that key 
      if new_entry is None: 
       new_entry = {key:value for key,value in entry.items()} 
       for key,value in new_entry.items(): 
      if not type(value) == str: 
       new_entry[key] = 0.0 
      for key,value in entry.items(): 
       if type(value) == str: 
        if not new_entry[key] == value: 
         raise Exception("Cannot merge different string for Key {}: {}, {}".format(key,value, new_entry[key])) 
       else: 
        new_entry[key] += value 
     new_entries.append(new_entry) 
    return new_entries 

마지막으로 약간의 지능형리스트와 함께 최고 수준의 코드는 간단하다 :

2014/01/01  A   100   
2014/01/01  B   60 
---------------------------------  
Value error A , B 

>>> entries = [ {"Date":"aaaa", "ItemType":"A", "Sales":10, "Partner":"P1"}, 
       {"Date":"aaaa", "ItemType":"A", "Sales":15, "Partner":"P2"}, 
       {"Date":"cccc", "ItemType":"A", "Sales":15, "Partner":"P2"}, 
       {"Date":"bbbb", "ItemType":"A", "Sales":15, "Partner":"P2"}, 
       {"Date":"bbbb", "ItemType":"B", "Sales":10, "Partner":"P3"}, 
       {"Date":"bbbb", "ItemType":"B", "Sales":15, "Partner":"P2"}, 
       {"Date":"cccc", "ItemType":"B", "Sales":10, "Partner":"P3"}] 

>>> f_entries = filter_entries(entries, "ItemType") 
>>> e_entries = {key:expand_entries(entries, "Partner") for key, entries in f_entries.items()} 
>>> m_entries = {key:merge_entries(entries, "Date") for key, entries in e_entries.items()} 

>>> for key in m_entries.keys(): 
     print key 
     for entry in m_entries[key]: 
      print entry 

A 
{'Date': 'aaaa', 'P2': 1.0, 'P1': 1.0, 'ItemType': 'A', 'Sales': 25.0} 
{'Date': 'cccc', 'P2': 1.0, 'P1': 0.0, 'ItemType': 'A', 'Sales': 15.0} 
{'Date': 'bbbb', 'P2': 1.0, 'P1': 0.0, 'ItemType': 'A', 'Sales': 15.0} 
B 
{'Date': 'cccc', 'P2': 0.0, 'Sales': 10.0, 'ItemType': 'B', 'P3': 1.0} 
{'Date': 'bbbb', 'P2': 1.0, 'Sales': 25.0, 'ItemType': 'B', 'P3': 1.0} 

저는 이 형식으로 테이블에 파일을 쓰는 것은 어렵지 않을 것입니다!

0

pandas에 익숙해 지려면 약간의 시간이 걸릴 수 있습니다. 내가 말할 수있는 것은 IPython 콘솔에서 놀고 처음부터 구현하는 것보다 작동하는 무언가를 찾는 데 훨씬 적은 시간이 걸린다는 것입니다.

찾고 계신 항목은 기본적으로 ItemType에 groupby, 파트너에는 pivot, 그 다음은 rolling_sum입니다. 이 작업을 매우 간결하게하는 몇 가지 방법이 있지만 간단히 데이터를 그룹으로 나누고 필요에 따라 처리 한 다음 끝에 그룹을 다시 구성하면 내가하는 일을 이해하는 것이 더 쉽습니다.

import pandas as pd 

df = pd.read_csv("sales.txt", delim_whitespace=True, parse_dates=[0]) 
df["Sales"] = df["Sales"].str.replace("$","").astype(float) 

last_n_dates = 2 

processed = [] 
grouped = df.groupby("ItemType") 
for item, group in grouped: 

    recent_sales = pd.rolling_sum(group["Sales"], last_n_dates, min_periods=1) 

    partners = pd.crosstab(group.Date, group.Partner) 
    recent_partners = pd.rolling_sum(partners, last_n_dates, min_periods=1) 

    group["Sales"] = recent_sales 
    del group["Partner"] 
    group = group.set_index("Date") 
    new_group = pd.concat([group, recent_partners], axis=1) 
    processed.append(new_group) 

df_final = pd.concat(processed).fillna(0) 

같은

뭔가 나에게 내가 의도적으로 충분한 값이 여기에 10이 재미있는 수 없기 때문에, 10이 아니라에 last_n_dates을 설정

>>> print(df_final) 
      ItemType P1 P2 P3 Sales 
Date         
2014-01-01  A 0 1 0 100 
2014-01-04  A 0 2 0 170 
2014-01-08  A 0 1 1 110 
2014-01-01  B 1 0 0  60 
2014-01-06  B 1 1 0 140 
2014-01-09  B 0 2 0 100 

[6 rows x 5 columns] 

참고를 제공합니다. 그러나 110 = 70 + 40이므로 괜찮아 보입니다.

+0

감사합니다. 너를 위해 너를 대단히 너. 불행히도, 출력에서 ​​나는 소스 파일에없는 날짜를 얻습니다. 어떻게 가능합니까? 어쩌면 그룹화가 ItemType에 의해서만 이루어져서는 안됩니까? – user3519466

+0

나는 날짜 형식을 섞어서 날짜를 가장 먼저, 다음 달을 순서대로 정렬했습니다. – user3519466

+0

그것은 작동합니다! 정말 고맙습니다. 현재 행의 영업 파트너를 제외한 이전 10 개 항목의 총계/총 수를 계산하는 방법이 있습니까? – user3519466

관련 문제