我正在尝试将 df2['values'] 中的列中的值分配给 df1['values'] 列的值。但是,只有在以下情况下才应分配值:
- df2["类别"] 等于 df1["类别"](行属于同一类别(
- df1["日期"] 位于 df2["date_range"] 中(特定类别的日期在特定范围内(
到目前为止,我有这段代码,它可以工作,但效率远非高,因为处理两个 dfs 需要两天时间(df1 大约有 700k 行(。
for i in df1.category.unique():
for j in df2.category.unique():
if i == j: # matching categories
for ia, ra in df1.loc[df1['category'] == i].iterrows():
for ib, rb in df2.loc[df2['category'] == j].iterrows():
if df1['date'][ia] in df2['date_range'][ib]:
df1.loc[ia, 'values'] = rb['values']
break
我读到在处理数据帧时应该尽量避免使用 for 循环。列表理解很棒,但是由于我还没有很多经验,所以我很难制定更复杂的代码。
如何更有效地迭代此问题?在迭代有条件的数据帧时,我应该考虑哪些重要的关键方面?
上面的代码倾向于跳过一些行或错误地分配它们,所以我需要在之后进行清理。最大的问题是,它真的很慢。
谢谢。
一些 df1 见解:
df1.head()
date category
0 2015-01-07 f2
1 2015-01-26 f2
2 2015-01-26 f2
3 2015-04-08 f2
4 2015-04-10 f2
一些 df2 见解:
df2.date_range[0]
DatetimeIndex(['2011-11-02', '2011-11-03', '2011-11-04', '2011-11-05',
'2011-11-06', '2011-11-07', '2011-11-08', '2011-11-09',
'2011-11-10', '2011-11-11', '2011-11-12', '2011-11-13',
'2011-11-14', '2011-11-15', '2011-11-16', '2011-11-17',
'2011-11-18'],
dtype='datetime64[ns]', freq='D')
DF2 其他两列:
df2[['values','category']].head()
values category
0 01 f1
1 02 f1
2 2.1 f1
3 2.2 f1
4 03 f1
编辑:更正了错误的代码并从注释中添加了 OP 输入
好的,如果您想加入类似类别的数据帧,您可以merge
它们:
import pandas as pd
df3 = df1.merge(df2, on = "category")
接下来,由于date
是一个时间戳,而"date_range"实际上是从两列生成的,根据 OP 的评论,我们宁愿使用:
mask = (df3["startdate"] <= df3["date"]) & (df3["date"] <= df3["enddate"])
subset = df3.loc[mask]
现在我们回到df1
并合并公共日期,同时保留所有值df1
.这将为子集值创建NaN
,其中子集值与早期合并中的df1
不匹配。
因此,我们将df1["values"]
设置了不NaN
共同条目的位置,否则我们将它们保留。
common_dates = df1.merge(subset, on = "date", how= "left") # keeping df1 values
df1["values"] = np.where(common_dates["values_y"].notna(),
common_dates["values_y"], df1["values"])
注意:如果多个df1["date"]
与日期范围匹配,则必须删除一些值,否则重复会使解释混乱。
你可以完成第一点:
1. DF2["类别"]等于 DF1["类别"]
使用联接。
然后,您可以使用 for 循环来过滤合并数据帧内 df1[date] 中未考虑的 df2[date_range] 中的数据位置。不幸的是,我需要更多关于 df1[date] 和 df2[date_range] 内容的信息来编写完全可以做到这一点的代码。