【问题标题】:How can I replicate excel COUNTIFS in python/pandas?如何在 python/pandas 中复制 excel COUNTIFS?
【发布时间】:2016-10-26 20:44:50
【问题描述】:

我想计算 df['A'] 中前 5 个值中的 # 个,它们是 = df2['A']。我试图避免循环遍历每一行和每一列,因为我想将其应用于更大的数据集。

鉴于此...

list1 = [[21,101],[22,110],[25,113],[24,112],[21,109],[28,108],[30,102],[26,106],[25,111],[24,110]]
df = pd.DataFrame(list1,index=pd.date_range('2000-1-1',periods=10, freq='D'), columns=list('AB'))
df2 = pd.DataFrame(df * (1-.05))

我想返回这个(在 Excel 中用 COUNTIFS 解决)...

下面的行实现了第一部分(感谢 Alexander),Divakar 和 DSM 之前也参与过(herehere)。

df3 = pd.DataFrame(df.rolling(center=False,window=6).apply(lambda rollwin: sum((rollwin[:-1] < rollwin[-1]))))

但我无法将比较添加到 df2。请帮忙。

2016 年 10 月 27 日跟进:

如何将上面的 lambda 编写为标准函数?

16 年 10 月 28 日:

见下文,从 df 和 df2 中获取 col 'A',我试图计算 df['A'] 的前 5 个值中有多少落在当前 df2['A'] 和 df['一种']。换句话说,每个橙色框有多少个落在黄色低-高范围之间?

更新:不同的 list1 数据产生不正确的 df3...

list1 = [[21,101],[22,110],[25,113],[24,112],[21,109],[26,108],[25,102],[26,106],[25,111],[22,110]]
df = pd.DataFrame(list1,index=pd.date_range('2000-1-1',periods=10, freq='D'), columns=list('AB'))
df2 = pd.DataFrame(df * (1-.05))

df3 = pd.DataFrame(
     df.rolling(center=False,window=6).apply(
          lambda rollwin: pd.Series(rollwin[:-1]).between(rollwin[-1]*0.95,rollwin[-1]).sum()))

df
Out[9]: 
             A    B
2000-01-01  21  101
2000-01-02  22  110
2000-01-03  25  113
2000-01-04  24  112
2000-01-05  21  109
2000-01-06  26  108
2000-01-07  25  102
2000-01-08  26  106
2000-01-09  25  111
2000-01-10  22  110


df3
Out[8]: 
              A    B
2000-01-01  NaN  NaN
2000-01-02  NaN  NaN
2000-01-03  NaN  NaN
2000-01-04  NaN  NaN
2000-01-05  NaN  NaN
2000-01-06  1.0  0.0
2000-01-07  2.0  0.0
2000-01-08  3.0  1.0
2000-01-09  2.0  3.0
2000-01-10  1.0  3.0

EXCEL 示例 (11/14):见下文,尝试计算蓝色框中有多少数字落在以橙色突出显示的范围之间。

【问题讨论】:

  • 您的df2 不可重现。 df_data 此处未定义。
  • 固定 Psidom。谢谢。
  • 我们会整理并回答这个问题吗?
  • 抱歉有什么我没有做的吗?我赞成您的两个答案并选择了第二个,因为它更简洁供其他人查看。很好的答案,非常感谢您的宝贵时间。
  • 在单独的说明中,我没有发现有关操作 df.rolling() 对象的文档与许多其他主题一样充实。将下面的 0.95 替换为相同滚动数据的另一个推导会很有用。

标签: python pandas dataframe boolean countif


【解决方案1】:
list1 = [[21,50,101],[22,52,110],[25,49,113],[24,49,112],[21,55,109],[28,54,108],[30,57,102],[26,56,106],[25,58,111],[24,60,110]]
df = pd.DataFrame(list1,index=pd.date_range('2000-1-1',periods=10, freq='D'), columns=list('ABC'))

print df

我相信这与您的新屏幕截图“给定数据”相符。

             A   B    C
2000-01-01  21  50  101
2000-01-02  22  52  110
2000-01-03  25  49  113
2000-01-04  24  49  112
2000-01-05  21  55  109
2000-01-06  28  54  108
2000-01-07  30  57  102
2000-01-08  26  56  106
2000-01-09  25  58  111
2000-01-10  24  60  110

和同样的功能:

print pd.DataFrame(
           df.rolling(center=False,window=6).
              apply(lambda rollwin: pd.Series(rollwin[:-1]).
                   between(rollwin[-1]*0.95,rollwin[-1]).sum()))

给出你想要的输出“期望的结果”:

             A   B   C
2000-01-01 nan nan nan
2000-01-02 nan nan nan
2000-01-03 nan nan nan
2000-01-04 nan nan nan
2000-01-05 nan nan nan
2000-01-06   0   1   0
2000-01-07   0   1   0
2000-01-08   1   2   1
2000-01-09   1   2   3
2000-01-10   0   2   3

【讨论】:

  • 它有效。太感谢了。在 inclusive=True/False 之间切换很重要。
【解决方案2】:
list1 = [[21,101],[22,110],[25,113],[24,112],[21,109],[28,108],[30,102],[26,106],[25,111],[24,110]]
df = pd.DataFrame(list1,index=pd.date_range('2000-1-1',periods=10, freq='D'), columns=list('AB'))
df2 = pd.DataFrame(df * (1-.05))


window = 6
results = []
for i in range (len(df)-window+1):
    slice_df1 = df.iloc[i:i + window]
    slice_df2 = df2.iloc[i:i + window]
    compare1 = slice_df1['A'].iloc[-1]
    compare2 = slice_df2['A'].iloc[-1]
    a= slice_df1.iloc[:-1]['A'].between(compare2,compare1)  # series have a between metho
    results.append(a.sum())

df_res =  pd.DataFrame(data = results , index = df.index[window-1:] , columns = ['countifs'])
df_res = df_res.reindex(df.index,fill_value=0.0)
print df_res

which yields:

            countifs
2000-01-01    0.0000
2000-01-02    0.0000
2000-01-03    0.0000
2000-01-04    0.0000
2000-01-05    0.0000
2000-01-06    0.0000
2000-01-07    0.0000
2000-01-08    1.0000
2000-01-09    1.0000
2000-01-10    0.0000

但是

看到您的上限和下限、价值和价值之间存在逻辑关系 - 5%。那么这也许就是你想要的。

    df3 = pd.DataFrame(
         df.rolling(center=False,window=6).apply(
            lambda rollwin: sum(np.logical_and(
                                    rollwin[-1]*0.95 <= rollwin[:-1]
                                   ,rollwin[:-1] < rollwin[-1]) 
                                )))

如果您更喜欢 pd.Series.between() 方法:

df3 = pd.DataFrame(
     df.rolling(center=False,window=6).apply(
          lambda rollwin: pd.Series(rollwin[:-1]).between(rollwin[-1]*0.95,rollwin[-1]).sum()))

【讨论】:

  • 感谢 Dickster,非常感谢您的意见。虽然我正在研究您的解决方案,但我在上面的问题中添加了一些颜色 - 可能没有问得足够清楚。
  • 完美运行,再次感谢。我相信 .between() 方法优于第一种方法。我将作为一个新问题提出后续问题。
  • 很酷地指出了这一点 - 并归功于其他人在已实现的线程上显示的功能。
  • 嗨,Dickster - 进一步使用后,似乎有些不对劲。当我用 list1 = [[21,101],[22,110],[25,113],[24,112],[21,109],[26,108],[25,102],[26,106],[25,111],[22,110] 替换原来的 'list1' ]],Series.between() 解决方案的输出似乎不正确。有机会看看吗?
  • 我没有看到使用新数据的问题。你觉得哪里不对?
猜你喜欢
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多