将日期向量转换为范围的 Pythonic 方法?

标签 python pandas date datetime

我有一个 pandas DataFrame,每天一行,还有一些 bool 列。我想将它们转换为一个 DataFrame,其中包含这些列为 True 的范围

启动 DF 的示例:

import pandas as pd

t = True
f = False

df = pd.DataFrame(
    {'indic': [f, f, t, t, t, f, f, f, t, f, f, t, t, t, t]},
    index=pd.date_range("2018-01-01", "2018-01-15")
)

print(df)

            indic
2018-01-01  False
2018-01-02  False
2018-01-03   True
2018-01-04   True
2018-01-05   True
2018-01-06  False
2018-01-07  False
2018-01-08  False
2018-01-09   True
2018-01-10  False
2018-01-11  False
2018-01-12   True
2018-01-13   True
2018-01-14   True
2018-01-15   True

此 DataFrame 的列从 2018-01-03 到 2018-01-05 为 True,然后在 2018-01-09(仅一天),然后从 2018-01-12 到 2018-01-15 再次为 True。

我在这个例子中寻找的输出是这个 DF (日期对象而不是字符串也可以,甚至是首选):

desired_result = pd.DataFrame({
    'from': ["2018-01-03", "2018-01-09", "2018-01-12"],
    'to': ["2018-01-05", "2018-01-09", "2018-01-15"]
})

print(desired_result)

         from          to
0  2018-01-03  2018-01-05
1  2018-01-09  2018-01-09
2  2018-01-12  2018-01-15

作为扩展,在后续步骤中我希望它适用于多个列,例如:

df = pd.DataFrame(
    {
        'indic_A': [f, f, t, t, t, f, f, f, t, f, f, t, t, t, t],
        'indic_B': [f, f, f, f, f, f, f, f, t, t, t, t, t, f, f]
    },
    index=pd.date_range("2018-01-01", "2018-01-15")
)

desired_result = pd.DataFrame({
    'from': ["2018-01-03", "2018-01-09", "2018-01-12", "2018-01-09"],
    'to': ["2018-01-05", "2018-01-09", "2018-01-15", "2018-01-13"],
    'what': ["indic_A", "indic_A", "indic_A", "indic_B"]
})

print(desired_result)

         from          to     what
0  2018-01-03  2018-01-05  indic_A
1  2018-01-09  2018-01-09  indic_A
2  2018-01-12  2018-01-15  indic_A
3  2018-01-09  2018-01-13  indic_B

有没有一种Python式的、优雅的方法来做到这一点——甚至可能是pandas函数?

最佳答案

使用melt首先进行 reshape ,然后通过 cumsum 为唯一组创建辅助列,仅按boolean indexing过滤True和聚合agg按功能 firstlast :

df = df.rename_axis('date').reset_index().melt('date', var_name='ind', value_name='boolean')
df['new'] = (~df['boolean']).cumsum()
df = (df[df['boolean']]
         .groupby('new')
         .agg({'date':['first','last'], 'ind':'first'})
         .reset_index(drop=True))
df.columns = df.columns.map('_'.join)
print (df)
  date_first  date_last ind_first
0 2018-01-03 2018-01-05   indic_A
1 2018-01-09 2018-01-09   indic_A
2 2018-01-12 2018-01-15   indic_A
3 2018-01-09 2018-01-13   indic_B

关于将日期向量转换为范围的 Pythonic 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53295483/

相关文章:

sql-server - TSQL 日期时间大小

PHP - 将单独的日、月、年转换为 mysql 日期格式

python - pyplot.hist 中的直方图条不以 xticks 为中心

python - 如何处理 pandas 中重复的 "unique identifiers"

python - 对 Python 中的数据集进行分组

python - 有没有办法将新列添加到 Pandas 数据框,将新列的每个唯一值附加到数据框的每个现有行?

python ftplib.error_perm : 500 Protocol not supported

python - 无法调用之前用 exec 定义的类

python - Python 网络抓取、DataFrame 索引问题

mongodb golang 按日期限制结果