基于双条件为Python数据表新增列:标记国家年度首个日期
问题与解法
需求与原数据
现有如下数据表,需要新增一列:若该行是对应国家对应年份的首个日期(即该组内最小日期),标记为1,否则标记为0。
| Country | Year | Date |
|---|---|---|
| Spain | 2020 | 2020-08-10 |
| Germany | 2020 | 2020-08-10 |
| Italy | 2019 | 2020-08-11 |
| Spain | 2019 | 2020-08-20 |
| Spain | 2020 | 2020-06-10 |
你尝试的自定义函数存在几个问题:
- 直接操作全局DataFrame,没有基于传入的行数据判断
x==1是比较运算符,不是赋值,应该用x=1- 函数没有返回值,无法生成结果
- 逐行处理的思路效率低下,不符合Pandas的使用习惯
最优解法(Pandas矢量化操作)
推荐用groupby结合transform实现,高效且简洁:
import pandas as pd # 构造示例数据(已有df可跳过) data = { "Country": ["Spain", "Germany", "Italy", "Spain", "Spain"], "Year": [2020, 2020, 2019, 2019, 2020], "Date": ["2020-08-10", "2020-08-10", "2020-08-11", "2020-08-20", "2020-06-10"] } df = pd.DataFrame(data) # 先将Date转为日期类型,确保日期比较准确 df["Date"] = pd.to_datetime(df["Date"]) # 新增标记列 df["IsFirstDate"] = df.groupby(["Country", "Year"])["Date"].transform(lambda x: x == x.min()).astype(int) print(df)
运行后得到结果:
| Country | Year | Date | IsFirstDate |
|---|---|---|---|
| Spain | 2020 | 2020-08-10 | 0 |
| Germany | 2020 | 2020-08-10 | 1 |
| Italy | 2019 | 2020-08-11 | 1 |
| Spain | 2019 | 2020-08-20 | 1 |
| Spain | 2020 | 2020-06-10 | 1 |
逻辑说明
groupby(["Country", "Year"]):按国家和年份分组,把相同国家同年份的数据归为一组transform(lambda x: x == x.min()):在每个组内,判断每行的日期是否等于该组的最小日期,返回布尔值(True/False)astype(int):把布尔值转为1/0,符合需求的标记格式
若坚持使用自定义函数(不推荐)
如果一定要用自定义函数,需要修正逻辑并结合apply逐行处理:
def first_date(row): # 根据当前行的国家和年份,筛选对应组的最小日期 min_date = df[(df["Country"] == row["Country"]) & (df["Year"] == row["Year"])]["Date"].min() # 比较当前行日期,返回1或0 return 1 if row["Date"] == min_date else 0 df["IsFirstDate"] = df.apply(first_date, axis=1)
注意:这种方法在数据量较大时,效率远低于矢量化操作,因此优先推荐第一种解法。
内容的提问来源于stack exchange,提问作者Lasnik23
相关产品推荐
相关产品推荐

