Python - 对每行的最后10个日期中的值进行分组

时间:2014-04-10 13:35:33

标签: python

我正在尝试对每行的前10个日期中的值进行分组。我有一个包含列的.csv文件:日期,项目,销售,合作伙伴和我需要这样的结果:日期,项目,总和(销售)(过去10天与该特定项目的销售),所以只有销售项目分组。日期不是连续的(某些日期根本没有销售,所以我不能只从日期减去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

对于后者,我可能需要分组然后转置。 我想我需要使用Panda和/或num.py模块来完成这些分组,但我是Python的新手,我无法找到一个例子。

5 个答案:

答案 0 :(得分:1)

你不需要像Panda或numpy那样复杂的东西 - 这是一个相当简单的流程,比如csv module

你可以这样做:

  • 使用csv reader读取文件,因此您有

    之类的数据

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

  • 对此数据keyed on the date

  • 进行排序
  • 使用itertools.groupby按日期分组

  • 使用slice notationprint([1,2,3,4][:2]))获取10个日期

  • 使用csv模块显示或写入新文件

如果您遇到任何这些步骤的问题,请回来发布一个新问题!

答案 1 :(得分:0)

假设您在列表中读取csv并且l [0]是日期字段。您可以这样使用itertools

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应该包含一个元组列表(date,sum_of_sales在该日期)。

这是分组的一部分。如果您要在实际的datetime对象中解析日期并进行比较,以便按特定顺序打印值,请使用strptime

答案 2 :(得分:0)

我想我理解你的问题。此解决方案将采用日期,并在该日期之前找到最后N个销售额的总和。看看吧:

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)

鉴于你的样本输入保存在my_data.csv中,这将是输出:

>>> 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文件,但这对您来说应该不是问题。

答案 3 :(得分:0)

看到你是python的新手,我已经提出了一个不包含第三方实用程序的解决方案,这样你就可以学习python。这涉及首先将表条目分组为字符串和数字类型的项目字典列表。 我会把文件读给你

主文件中的空条目看起来像。

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

我已经完成了三项功能,可以完全满足您的需求。

  • filter_entries(entries, filter_key),返回一个字典 key:基于条目列表[filter_key]值全部相同的条目的条目列表项
  • expand_entries(entries, expand_key),返回一个带有的条目列表 删除entry-list [expand_key]并替换为基于的所有唯一键:值对 expand_key
  • merge_entries(entries, merge_key),根据条目返回一个条目列表,其中所有具有相同条目[merge_key]值的项目合并

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   

一个坏的案例如下:

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

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

最后,通过一点列表理解,顶级代码很简单:

>>> 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}

我确定使用此表格,将表格写入文件并不困难!

答案 4 :(得分: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)

给了我

>>> 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]

请注意,我故意将last_n_dates设置为2而不是10,因为这里没有足够的值来让10感兴趣。但是,110 = 70 + 40,所以看起来没问题。