【问题标题】:Pandas: Efficient equivalent for SQL-HAVING StatementPandas:SQL-HAVING 语句的高效等价物
【发布时间】:2013-07-08 20:20:06
【问题描述】:

我对 pandas 中的行选择有疑问。举个例子:

df = pd.DataFrame({
'Branch' : 'A A A A A B'.split(),
'Buyer': 'Carl Mark Carl Joe Mark Carl'.split(),
'Quantity': [1,3,5,8,9,3],
'Date' : [
    DT.datetime(2013,9,1,13,0),
    DT.datetime(2013,9,1,13,5),
    DT.datetime(2013,10,1,20,0),
    DT.datetime(2013,10,3,10,0),
    DT.datetime(2013,12,2,12,0),                                      
    DT.datetime(2013,12,2,14,0),
    ]})

我想有效地找到“Carl”“Mark”购买东西的那些日子,包括相应的购买日期。比如这样的

                     Date_1 Buyer_1                Date Buyer
Day                                                                
2013-09-01 2013-09-01 13:00:00       Carl 2013-09-01 13:05:00  Mark
2013-12-02 2013-12-02 14:00:00       Carl 2013-12-02 12:00:00  Mark

为此,我目前正在使用以下代码:

df['Day'] = df.Date.map(lambda t: t.date())
df = df.set_index('Day')
day1 = df[df.Buyer == 'Carl'][['Date', 'Buyer']]
day2 = df[df.Buyer == 'Mark'][['Date', 'Buyer']]
test1 = day1.join(day2, lsuffix='_1')
test1 = test1.dropna()

但是,这段代码执行不正常(timeit.timeit(mytest, number=1000)) ~ 4s

有没有人知道如何提高该计算的性能并保持可读性?

我将不胜感激。

安迪

【问题讨论】:

    标签: python performance pandas


    【解决方案1】:

    试试这个:

    In [69]: df[df['Buyer'].isin(['Carl', 'Mark'])].set_index('Buyer', append=True)[['Date']].unstack(['Buyer'])
    Out[69]: 
                              Date                    
    Buyer                     Carl                Mark
    Day                                               
    2013-09-01 2013-09-01 13:00:00 2013-09-01 13:05:00
    2013-10-01 2013-10-01 20:00:00                 NaT
    2013-12-02 2013-12-02 14:00:00 2013-12-02 12:00:00
    

    【讨论】:

    • 不确定是否这样做,因为 OP 询问“那些日子“卡尔”和“马克”买了东西……”(尽管我同意请求是一种相当奇怪的显示格式)。 :s
    【解决方案2】:

    如果您不将索引设置为 Day,那么您可以使用 filter(即将推出 0.12!):

    In [11]: df
    Out[11]:
              Day Branch Buyer                Date  Quantity
    0  2013-09-01      A  Carl 2013-09-01 13:00:00         1
    1  2013-09-01      A  Mark 2013-09-01 13:05:00         3
    2  2013-10-01      A  Carl 2013-10-01 20:00:00         5
    3  2013-10-03      A   Joe 2013-10-03 10:00:00         8
    4  2013-12-02      A  Mark 2013-12-02 12:00:00         9
    5  2013-12-02      B  Carl 2013-12-02 14:00:00         3
    
    In [12]: g = df.groupby('Day', as_index=False)
    
    In [13]: df1 = g.filter(lambda row: set(['Carl', 'Mark']).issubset(set(row.Buyer)))
    
    In [14]: df1
    Out[14]:
              Day Branch Buyer                Date  Quantity
    0  2013-09-01      A  Carl 2013-09-01 13:00:00         1
    1  2013-09-01      A  Mark 2013-09-01 13:05:00         3
    4  2013-12-02      A  Mark 2013-12-02 12:00:00         9
    5  2013-12-02      B  Carl 2013-12-02 14:00:00         3
    

    然后也许使用pivot_table:

    In [15]: df1.pivot_table('Quantity', 'Day', 'Buyer')
    Out[15]:
    Buyer       Carl  Mark
    Day
    2013-09-01     1     3
    2013-12-02     3     9
    
    In [16]: df1.pivot_table(['Date', 'Quantity'], 'Day', 'Buyer',
                             aggfunc=lambda t: t.values[0])
    Out[16]:
                               Date                      Quantity
    Buyer                      Carl                 Mark     Carl Mark
    Day
    2013-09-01  2013-09-01 13:00:00  2013-09-01 13:05:00        1    3
    2013-12-02  2013-12-02 14:00:00  2013-12-02 12:00:00        3    9
    

    考虑一下,也许先做支点更有意义:

    In [21]: pv1 = df.pivot_table('Quantity', 'Day', 'Buyer')
    
    In [22]: pv1[pd.notnull(pv1['Mark']) & pd.notnull(pv1['Carl'])]
    Out[22]:
    Buyer       Carl  Joe  Mark
    Day
    2013-09-01     1  NaN     3
    2013-12-02     3  NaN     9
    
    In [22]: pv2 = df.pivot_table(['Date', 'Quantity'], 'Day', 'Buyer',
                                  aggfunc=lambda t: t.values[0])
    
    In [23]: pv2[pd.notnull(pv2[('Quantity', 'Mark')]) & pd.notnull(pv2[('Quantity', 'Carl')])]
    Out[23]:
                                              Date                                          Quantity
    Buyer                                     Carl  Joe                                Mark     Carl  Joe Mark
    Day
    2013-09-01  2013-09-01T14:00:00.000000000+0100  NaN  2013-09-01T14:05:00.000000000+0100        1  NaN    3
    2013-12-02  2013-12-02T14:00:00.000000000+0000  NaN  2013-12-02T12:00:00.000000000+0000        3  NaN    9
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      • 2012-09-27
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多