【问题标题】:Count value between datetime and NaT日期时间和 NaT 之间的计数值
【发布时间】:2021-02-12 23:08:32
【问题描述】:

我有两个 python pandas 数据框,它们的简化形式如下所示:

DF1

+---------+---------+------+-------+
| Date_in | Date_out| Group| Item  |
+---------+---------+------+-------+
| 1991-08 | 2000-08 |   A  |   A1  |
| 1992-08 |   NaT   |   A  |   A2  |
| 1997-02 |   NaT   |   B  |   B1  |
| 1998-03 | 2001-03 |   C  |   C1  |
| 1999-02 | 2002-02 |   D  |   D1  |
| 2000-02 |   NaT   |   D  |   D2  |
| 2000-03 | 2001-04 |   D  |   D3  |
| 2001-08 |   NaT   |   D  |   D4  |
+---------+---------+------+-------+

DF2

+---------+-------+
|  Date   | Group | 
+---------+-------+
| 2000-01 |   A   | 
| 2001-02 |   A   | 
| 2001-03 |   B   |
| 2001-04 |   B   | 
| 2001-05 |   C   | 
| 2001-06 |   C   |
| 2001-03 |   D   |
| 2001-07 |   D   |
+---------|-------+

我想根据 DF1 中的日期约束计算组列 DF2 中还存在多少项目

期望的输出

+---------+-------+-------+
|  Date   | Group | Total |
+---------+-------+-------+
| 2000-01 |   A   |   2   |
| 2001-02 |   A   |   1   |
| 2001-03 |   B   |   1   |
| 2001-04 |   B   |   1   |
| 2001-05 |   C   |   0   |
| 2001-06 |   C   |   0   |
| 2001-03 |   D   |   3   |
| 2001-07 |   D   |   2   |
+---------|-------+-------+

【问题讨论】:

  • 获得所需输出的逻辑是什么?
  • 是的,@jezrael 先生,因为 A1(2000-08 年推出)在 2000-01 年仍然存在
  • 知道了。刚刚想通了。我认为@jezrael 太快了。他已经回答了
  • @JoeFerndz - Nat 表示仍然存在

标签: pandas dataframe map-function


【解决方案1】:

您可以在第一步中先转换所有日期时间并将缺少的NaT 替换为今天的日期:

df2['Date'] = pd.to_datetime(df2['Date'])

df1['Date_in'] = pd.to_datetime(df1['Date_in'])
df1['Date_out'] = pd.to_datetime(df1['Date_out']).fillna(pd.to_datetime('now').normalize())
print (df1)
     Date_in   Date_out Group Item
0 1991-08-01 2000-08-01     A   A1
1 1992-08-01 2021-02-12     A   A2
2 1997-02-01 2021-02-12     B   B1
3 1998-03-01 2001-03-01     C   C1
4 1999-02-01 2002-02-01     D   D1
5 2000-02-01 2021-02-12     D   D2
6 2000-03-01 2001-04-01     D   D3
7 2001-08-01 2021-02-12     D   D4

然后获取Date_inDate_out 之间的所有月份,并按GrouperGroupBy.size 分组计算月份:

L = [pd.Series(r.Group,pd.date_range(r.Date_in, r.Date_out, freq='MS')) 
     for r in df1.itertuples()]
s = (pd.concat(L)
         .reset_index(name='Group')
         .groupby([pd.Grouper(key='index', freq='MS'), 'Group'])
         .size()
         .rename('Total'))

# print (s)

最后使用DataFrame.join 添加新列并将NaN 替换为0 以防止不匹配的值:

df2 = df2.join(s, on=['Date','Group'])
df2['Total'] = df2['Total'].fillna(0).astype(int)
print (df2)
        Date Group  Total
0 2000-01-01     A      2
1 2001-02-01     A      1
2 2001-03-01     B      1
3 2001-04-01     B      1
4 2001-05-01     C      0
5 2001-06-01     C      0
6 2001-03-01     D      3
7 2001-07-01     D      2

编辑:

在实际数据中需要使用days,而不是日期时间,因此对解决方案进行了一些修改:

#remove times
df2['date'] = df2['created_at'].dt.normalize()

#convert date_range by days
L = [pd.Series(r.dept_name,pd.date_range(r.start_date, r.end_date, freq='d')) 
     for r in df1.itertuples()]
s = (pd.concat(L)
    .reset_index(name='dept_name')
    .groupby([pd.Grouper(key='index', freq='D'), 'dept_name'])
    .size()
    .rename('total_member'))

#join by column date (without times)
df2 = df2.join(s, on=['date','dept_name'])
df2['total_member'] = df2['total_member'].fillna(0).astype(int)

【讨论】:

  • 仍然想知道为什么我在 Total 列中的所有值仍然为零?
  • @yogapurbaya - df2['Date'] = pd.to_datetime(df2['Date']) df1['Date_in'] = pd.to_datetime(df1['Date_in']) df1['Date_out'] = pd.to_datetime(df1['Date_out']).fillna(pd.to_datetime('now').normalize()) 之后的日期时间是否正确?
  • 检查print (df1)print (df2)
  • 是的,每个日期列都是正确的 dtype: datetime64[ns]
  • @yogapurbaya - 是的,但如果匹配 - 这意味着如果在 df1 日期时间之间的df2 日期时间中存在。
猜你喜欢
  • 1970-01-01
  • 2022-11-21
  • 2010-09-17
  • 2023-03-11
  • 2014-09-28
  • 2018-10-14
  • 2020-10-19
  • 2021-10-09
相关资源
最近更新 更多