Pandas 打印数据框列中条件成立的日期期间?
Pandas print date periods where a condition holds in a data frame column?
我有一个文本文件。如下所示的文件:
Name 1
@Name( ) Value WATER WHP
Date Unit Unit Unit
-------------- ---------- ---------- ---------- ----------
Name 1 20081220 2900.00 0.00 3300.00
Name 1 20081221 0.00 0.00 3390.00
Name 1 20081222 2500.00 0.00 2802.00
Name 1 20081223 0.00 0.00 3022.00
Name 1 20081224 0.00 0.00 3022.00
我使用以下代码导入 python:
df = pd.read_csv(r'test_prd.txt', skiprows=6, engine="python", header=None)
df.columns = ['Test']
df.drop(df.tail(1).index, inplace = True) # because of file format
df = df.Test.str.split(expand=True)
df.rename(columns ={0:'Name', 1:'Number', 2:'Date', 3:'Value', 4:'Water', 5:'WHP'}
,inplace=True)
df['Date'] = pd.to_datetime(df['Date']).dt.floor('D').dt.strftime('%Y-%m-%d')
df['Note'] = (df['Value']).apply(lambda x: 'yes' if x==0 else '')
del df['Water']
del df['WHP']
df['Name'] = df['Name'].astype(str) + ' ' + df['Number'].astype(str)
del df['Number']
使用此代码后,数据框如下所示:
Name Date Value Note
0 Name 1 2008-12-20 2900.00
1 Name 1 2008-12-21 0.00 Yes
2 Name 1 2008-12-22 2500.00
3 Name 1 2008-12-23 0.00 Yes
4 Name 1 2008-12-24 0.00 Yes
... ... ... ... ...
78 Name 2009-03-15 0.00 Yes
79 Name 2009-03-16 3000.00
80 Name 2009-03-17 0.00 Yes
... ... ... ... ...
我想打印 'Value' 列为零的时间段(开始日期 - 结束日期),即 'Note'=Yes。任何其他值为非零的行都可以从数据框中删除。如果存在零独立值(前后为非零值),则开始日期和结束日期将相同。
预期输出应如下所示:
Name Start Date End Date Value Note
1 Name 2008-12-21 2008-12-21 0.00 Yes
2 Name 2008-12-23 2009-03-15 0.00 Yes
3 Name 2009-03-17 *** 0.00 Yes
... ... ... ... ...
我试图使用条件 if 语句或 df.loc,但我不知道自己的方法 Python 足以将它们组合在一起。如有任何建议,我们将不胜感激。
对于 select 帧的 'Note' 列为是的所有行,使用:
df.loc[df['Note'] == 'Yes']
这会产生一个包含仅满足上述条件的行的框架。
更多有用的操作见:
How to select rows from a DataFrame based on column values
首先让我们使用 read_csv
导入您的数据框
df = PD.read_csv("yourfile.txt", sep="\s+", engine="python", parse_dates=["Date"])
df["Value"] = df["Value"].astype(float)
一定要用正确的列分隔符替换 sep
的值。这里我假设分隔符是一个或多个空格,如果不是请修改。
还要确保使用 parse_dates
参数将 "Date"
列转换为日期时间,并且 "Value"
列的类型为 float。
现在 df
作为您的数据框,此代码段应该可以满足您的要求。
df["Start"] = (df["Value"] == 0) & (df["Value"].shift(1) != 0)
ddf = df[df["Value"] == 0]
ddf["Group"] = ddf["Start"].cumsum()
rdf = ddf.groupby("Group").apply(lambda x: PD.Series({"Name":x["Name"].iloc[0],
"Start Date":x["Date"].min(),
"End Date":x["Date"].max(),
"Value": 0.,
"Note": "Yes",
})).reset_index(drop=True)
这里的重点是使用一些 pandas 函数以高效的方式实现您想要的。不要使用循环,如果你的数据帧很大,你将需要很多时间来执行你的代码。
- 在这里,我首先创建一个
"Start"
列,我在其中检查哪一行是零间隔行系列的开始。我通过将 "Value"
行向前移动 1 个位置,然后比较每一行来实现。 "Start"
列对于应该开始间隔的每一行都有一个 True 值。
- 然后我删除非零
"Value"
行。
- 然后我使用
cumsum
对“开始”列求和。这将创建一个新列,我可以用它来将应该加入的间隔组合在一起。
- 最终我可以使用
groupby
和 apply
将组连接在一起,并为每个组创建一个新数据框的一行,我可以从中获取最早和最晚的日期 "Date"
列。
根据您发布的行数,最终结果为:
Name Start Date End Date Value Note
0 Name 2008-12-21 2008-12-21 0.0 Yes
1 Name 2008-12-23 2009-03-15 0.0 Yes
2 Name 2009-03-17 2009-03-17 0.0 Yes
我有一个文本文件。如下所示的文件:
Name 1
@Name( ) Value WATER WHP
Date Unit Unit Unit
-------------- ---------- ---------- ---------- ----------
Name 1 20081220 2900.00 0.00 3300.00
Name 1 20081221 0.00 0.00 3390.00
Name 1 20081222 2500.00 0.00 2802.00
Name 1 20081223 0.00 0.00 3022.00
Name 1 20081224 0.00 0.00 3022.00
我使用以下代码导入 python:
df = pd.read_csv(r'test_prd.txt', skiprows=6, engine="python", header=None)
df.columns = ['Test']
df.drop(df.tail(1).index, inplace = True) # because of file format
df = df.Test.str.split(expand=True)
df.rename(columns ={0:'Name', 1:'Number', 2:'Date', 3:'Value', 4:'Water', 5:'WHP'}
,inplace=True)
df['Date'] = pd.to_datetime(df['Date']).dt.floor('D').dt.strftime('%Y-%m-%d')
df['Note'] = (df['Value']).apply(lambda x: 'yes' if x==0 else '')
del df['Water']
del df['WHP']
df['Name'] = df['Name'].astype(str) + ' ' + df['Number'].astype(str)
del df['Number']
使用此代码后,数据框如下所示:
Name Date Value Note
0 Name 1 2008-12-20 2900.00
1 Name 1 2008-12-21 0.00 Yes
2 Name 1 2008-12-22 2500.00
3 Name 1 2008-12-23 0.00 Yes
4 Name 1 2008-12-24 0.00 Yes
... ... ... ... ...
78 Name 2009-03-15 0.00 Yes
79 Name 2009-03-16 3000.00
80 Name 2009-03-17 0.00 Yes
... ... ... ... ...
我想打印 'Value' 列为零的时间段(开始日期 - 结束日期),即 'Note'=Yes。任何其他值为非零的行都可以从数据框中删除。如果存在零独立值(前后为非零值),则开始日期和结束日期将相同。
预期输出应如下所示:
Name Start Date End Date Value Note
1 Name 2008-12-21 2008-12-21 0.00 Yes
2 Name 2008-12-23 2009-03-15 0.00 Yes
3 Name 2009-03-17 *** 0.00 Yes
... ... ... ... ...
我试图使用条件 if 语句或 df.loc,但我不知道自己的方法 Python 足以将它们组合在一起。如有任何建议,我们将不胜感激。
对于 select 帧的 'Note' 列为是的所有行,使用:
df.loc[df['Note'] == 'Yes']
这会产生一个包含仅满足上述条件的行的框架。
更多有用的操作见: How to select rows from a DataFrame based on column values
首先让我们使用 read_csv
df = PD.read_csv("yourfile.txt", sep="\s+", engine="python", parse_dates=["Date"])
df["Value"] = df["Value"].astype(float)
一定要用正确的列分隔符替换 sep
的值。这里我假设分隔符是一个或多个空格,如果不是请修改。
还要确保使用 parse_dates
参数将 "Date"
列转换为日期时间,并且 "Value"
列的类型为 float。
现在 df
作为您的数据框,此代码段应该可以满足您的要求。
df["Start"] = (df["Value"] == 0) & (df["Value"].shift(1) != 0)
ddf = df[df["Value"] == 0]
ddf["Group"] = ddf["Start"].cumsum()
rdf = ddf.groupby("Group").apply(lambda x: PD.Series({"Name":x["Name"].iloc[0],
"Start Date":x["Date"].min(),
"End Date":x["Date"].max(),
"Value": 0.,
"Note": "Yes",
})).reset_index(drop=True)
这里的重点是使用一些 pandas 函数以高效的方式实现您想要的。不要使用循环,如果你的数据帧很大,你将需要很多时间来执行你的代码。
- 在这里,我首先创建一个
"Start"
列,我在其中检查哪一行是零间隔行系列的开始。我通过将"Value"
行向前移动 1 个位置,然后比较每一行来实现。"Start"
列对于应该开始间隔的每一行都有一个 True 值。 - 然后我删除非零
"Value"
行。 - 然后我使用
cumsum
对“开始”列求和。这将创建一个新列,我可以用它来将应该加入的间隔组合在一起。 - 最终我可以使用
groupby
和apply
将组连接在一起,并为每个组创建一个新数据框的一行,我可以从中获取最早和最晚的日期"Date"
列。
根据您发布的行数,最终结果为:
Name Start Date End Date Value Note
0 Name 2008-12-21 2008-12-21 0.0 Yes
1 Name 2008-12-23 2009-03-15 0.0 Yes
2 Name 2009-03-17 2009-03-17 0.0 Yes