【问题标题】:How to slice pandas DataFrame based on values from another Dataframe without using for-loop?如何在不使用 for 循环的情况下根据来自另一个 Dataframe 的值对 pandas DataFrame 进行切片?
【发布时间】:2016-06-10 11:01:00
【问题描述】:

我有一个 DataFrame df1

df1.head() =    
             id    type    position
dates
2000-01-03  17378   600       400
2000-01-03   4203   600       150
2000-01-03  18321   600      5000
2000-01-03   6158   600      1000
2000-01-03    886   600     10000
2000-01-03  17127   600       800
2000-01-03  18317  1300       110
2000-01-03   5536   600       207
2000-01-03   5132   600     20000
2000-01-03  18191   600      2000       

还有第二个 DataFrame df2

df2.head() = 

               dt_f       dt_l
id_y  id_x
670   715   2000-02-14 2003-09-30
704   2963  2000-02-11 2004-01-13
886   18350 2000-02-09 2001-09-24
1451  18159 2005-11-14 2007-03-06
2175  8648  2007-02-28 2007-09-19
2236  18321 2001-04-05 2002-07-02
2283  2352  2007-03-07 2007-09-19
      6694  2007-03-07 2007-09-17
      13865 2007-04-19 2007-09-19
      14348 2007-08-10 2007-09-19
      15415 2007-03-07 2007-09-19
2300  2963  2001-05-30 2007-09-26

我需要为id_x 的每个值分割df1,并计算区间dt_f:dt_l 内的行数。对于id_y 的值,必须再次执行此操作。最后结果应该在df2 上合并,输出如下DataFrame:

df_result.head() = 

               dt_f       dt_l     n_x   n_y
id_y  id_x
670   715   2000-02-14 2003-09-30   8     10 
704   2963  2000-02-11 2004-01-13   13    25 
886   18350 2000-02-09 2001-09-24   32    75
1451  18159 2005-11-14 2007-03-06   48    6 

其中n_x(n_y) 对应于每个id_x(id_y 值的区间dt_f:dt_l 中包含的行数。

这是我用过的for循环:

idx_list = df2.index.tolist()
k = 1 
for j in idx_list: 
    n_y = df1[df1.id == j[0]][df2['dt_f'].iloc[k]:df2['dt_l'].iloc[k]]['id'].count() 
    n_x = df1[df1.id == j[1]][df2['dt_f'].iloc[k]:df2['dt_l'].iloc[k]]['id'].count() 

不使用 for 循环是否可以做到这一点? DataFrame df1包含大约 30000 行,我担心循环会大大减慢进程,因为这是整个脚本的一小部分。

【问题讨论】:

  • 为什么n_yn_x 不同?你能告诉我们你的for循环吗?
  • 您对当前的答案满意吗?作为旁注,您应该检查如何发布minimal reproducible example。理想情况下,您的输入将导致您想要的输出,这将使人们更容易检查他们的答案(并理解问题)。
  • 感谢 IanS 的 cmets

标签: python pandas merge vectorization slice


【解决方案1】:

你想要这样的东西:

#Merge the tables together - making sure we keep the index column
mg = df1.reset_index().merge(df2, left_on = 'id', right_on = 'id_x')

#Select only the rows that are within the start and end
mg = mg[(mg['index'] > mg['dt_f']) & (mg['index'] < mg['dt_l'])]

#Finally count by id_x
mg.groupby('id_x').count()

之后您需要整理列并重复 id_y。

【讨论】:

  • 非常感谢!它完美地工作! (我已经通过重置 df 和我使用 mg['dates'] 而不是 mg['index'] 上的索引来适应我的代码)
猜你喜欢
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多