【问题标题】:Using Pandas to build a 2D table based on COUNTIF()'s of a separate excel sheet使用 Pandas 基于单独的 Excel 表的 COUNTIF() 构建 2D 表
【发布时间】:2017-09-28 03:24:00
【问题描述】:

我想根据另一个表中的值(和计数)构建一个二维表。我设法使用 Excel 成功地对此进行了原型设计,但是我被两个概念困住了:

1. Emulating Excel COUNTIF() on pandas
2. Dynamically build a new dataframe

注意:COUNTIF() 将范围和条件作为参数。例如,如果我有一个颜色列表,并且我想知道“橙色”出现在下面列表中的次数:

A
Red
Orange
Blue
Orange
Black

,那么我会简单地使用以下公式:

COUNTIF(A1:A5, "Orange")

这应该返回 2。

当然 COUNTIF() 函数可以变得更复杂,例如这种形式的连接条件示例 COUNTIF(range1,criteria1,range2,criteria2...) 可以解释为 AND 条件。例如,如果我想在类似于以下的列表中计算 35 岁以上的女性:

A             B
Female        19
Female        40
Male          45

,那么我会简单地使用以下公式:

COUNTIF(A1:A3, "Female", B1:B3, ">35"

这应该返回 1。

回到我的用例。这是源表:

   Product No Opening Date Closing Date Opening Month Closing Month
0           1   2016-01-01   2016-06-30    2016-01-31    2016-06-30
1           2   2016-01-01   2016-04-30    2016-01-31    2016-04-30
2           3   2016-02-01   2016-06-30    2016-02-29    2016-06-30
3           4   2016-02-01   2016-05-31    2016-02-29    2016-05-31
4           5   2016-02-01   2099-12-31    2016-02-29    2099-12-31
5           6   2016-01-01   2099-12-31    2016-01-31    2016-10-31
6           7   2016-06-01   2016-07-31    2016-06-30    2016-07-31
7           8   2016-06-01   2016-11-30    2016-06-30    2016-11-30
8           9   2016-06-01   2016-07-31    2016-06-30    2016-07-31
9          10   2016-06-01   2099-12-31    2016-06-30    2099-12-31

这是我想要实现的二维矩阵:

            2016-01-31  2016-02-29  2016-03-31  2016-04-30  2016-05-31  \
2016-01-31           3           3           3           2           2
2016-02-29           3           3           3           3           2
2016-03-31           0           0           0           0           0
2016-04-30           0           0           0           0           0
2016-05-31           0           0           0           0           0
2016-06-30           4           4           4           4           4
2016-07-31           0           0           0           0           0
2016-08-31           0           0           0           0           0
2016-09-30           0           0           0           0           0
2016-10-31           0           0           0           0           0
2016-11-30           0           0           0           0           0
2016-12-31           0           0           0           0           0

            2016-06-30  2016-07-31  2016-08-31  2016-09-30  2016-10-31  \
2016-01-31           1           1           1           1           0
2016-02-29           1           1           1           1           1
2016-03-31           0           0           0           0           0
2016-04-30           0           0           0           0           0
2016-05-31           0           0           0           0           0
2016-06-30           4           2           2           2           2
2016-07-31           0           0           0           0           0
2016-08-31           0           0           0           0           0
2016-09-30           0           0           0           0           0
2016-10-31           0           0           0           0           0
2016-11-30           0           0           0           0           0
2016-12-31           0           0           0           0           0

            2016-11-30  2016-12-31
2016-01-31           0           0
2016-02-29           1           1
2016-03-31           0           0
2016-04-30           0           0
2016-05-31           0           0
2016-06-30           1           1
2016-07-31           0           0
2016-08-31           0           0
2016-09-30           0           0
2016-10-31           0           0
2016-11-30           0           0
2016-12-31           0           0

基本上我想建立一个产品随时间生存的矩阵。纵轴代表新产品的起源,而横轴衡量这些帐户中有多少随着时间的推移持续存在。

例如,如果在 1 月份推出了 10 种产品,则 1 月与 1 月的数字应为 10。如果这 10 种产品中的 1 种在 2 月关闭,则 1 月与 2 月的数字应为 9。如果所有剩余产品都到六月关闭,那么一月与六月、七月、八月等的行应该是 0。

2月、3月、4月等的产品开发不会影响1月的行。

我设法使用以下 excel 公式构建了二维矩阵:

=COUNTIF(Accounts!$D$2:$D$11,Main!$A2)-COUNTIFS(Accounts!$D$2:$D$11,Main!$A2, Accounts!$E$2:$E$11,"<="&Main!B$1)

(这将填充第一个单元格)

我最初的策略是构建一个多维列表并使用多个 for 循环来填充它们,但我不确定 Pandas 中是否有更简单(或更推荐的方式)。

【问题讨论】:

    标签: python excel pandas


    【解决方案1】:

    由于我还没有足够的声誉来评论你的问题,我将假设你的数据中有错别字,年份等于 2099。

    我还想问一下,在您的 2016-06-30 行中,如何在前几列(即 2016-01-31 到 2016-05-31)中有 4 个“产品编号”。

    如果这些是错误,那么这是我的解决方案:

    首先,制作数据:

    # Make dataframe
    df = pd.DataFrame({'Product No' : [i for i in range(1,11)],
                       'Opening Date' : ['2016-01-01']*2 +\
                                        ['2016-02-01']*3 +\
                                        ['2016-01-01'] +\
                                        ['2016-06-01']*4,
                       'Closing Date' : ['2016-06-30', '2016-04-30', '2016-06-30', '2016-05-31'] +\
                                        ['2016-12-31']*2 +\
                                        ['2016-07-31', '2016-11-30', '2016-07-31', '2016-12-31'],
                       'Opening Month' : ['2016-01-31']*2 +\
                                         ['2016-02-29']*3 +\
                                         ['2016-01-31'] +\
                                         ['2016-06-30']*4,
                       'Closing Month' : ['2016-06-30', '2016-04-30', '2016-06-30', '2016-05-31',
                                          '2016-12-31', '2016-10-31', '2016-07-31', '2016-11-30',
                                          '2016-07-31', '2016-12-31']})
    
    # Reorder columns
    df = df.loc[:, ['Product No', 'Opening Date', 'Closing Date',
                    'Opening Month', 'Closing Month']]
    
    # Convert dates to datetime
    for i in df.columns[1:]:
        df.loc[:, i] = pd.to_datetime(df.loc[:, i])
    

    其次,我创建了一个“日期范围”数据框,用于保存原始数据集的最小到最大日期。我还包括了一个“产品编号”列,以便每个产品在表格上都有一行:

    # Create date range dataframe
    daterange = pd.DataFrame({'daterange' : pd.date_range(start = df.loc[:, 'Opening Month'].min(),
                                                      end = df.loc[:, 'Closing Month'].max(),
                                                      freq = 'M'),
                              'Product No' : [1]*12})
    
    # Create 10 multiples of the daterange and concatenate
    daterange10 = pd.concat([daterange]*10)
    
    # Find the cumulative sum of the 'Product No' for daterange10
    daterange10.loc[:, 'Product No'] = daterange10.groupby('daterange').cumsum()
    

    第三,我将日期范围和原始 df 合并在一起,并将行限制为仅包含存在“产品编号”时。另请注意,我有它,因此关闭日期必须大于或等于日期范围,因为(在我看来)如果产品在当月的最后一天关闭,那么它在整个月内都存在:

    # Merge df with daterange10
    df = df.merge(daterange10,
                  how = 'inner',
                  on = 'Product No')
    
    # Limit rows to when 'Opening Month' is <= 'daterange' and 'Closing Month' is >= 'daterange'
    df = df[(df.loc[:, 'Opening Month'] <= df.loc[:, 'daterange']) &
            (df.loc[:, 'Closing Month'] >= df.loc[:, 'daterange'])]
    

    最后,我用日期值制作了一个数据透视表。请注意,它仅包括最初存在的垂直轴上的日期:

    # Pivot on 'Opening Month', 'daterange'; count unique 'Product No'; fill NA with 0
    df.pivot_table(index = 'Opening Month',
                   columns = 'daterange',
                   values = 'Product No',
                   aggfunc = pd.Series.nunique).fillna(0)
    

    【讨论】:

    • 非常容易理解,我设法学习了一些技巧。谢谢!
    【解决方案2】:

    尝试将您的数据放入 pandas DataFrame,然后使用迭代方法构建产品生存 DataFrame:

    import pandas as pd
    
    mydata = pd.read_excel('mysourcedata.xlsx')
    
    def product_survival(sourcedf, startdate, enddate):
    
        df = pd.DataFrame()
    
        daterange = pd.date_range(startdate, enddate, freq='M')
    
        for i in daterange: # Rows
            for j in daterange: # Columns
                mycount = sourcedf[(sourcedf['Opening Month'] == i) & (sourcedf['Closing Month'] > j)]['Product No'].count()
                df.loc[i, j] = mycount
    
        return df
    
    print(product_survival(mydata, '2016-01-31', '2016-12-31'))
    

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 1970-01-01
      • 2011-02-12
      相关资源
      最近更新 更多