【问题标题】:Assign value to dataframe from another dataframe based on two conditions根据两个条件从另一个数据帧为数据帧赋值
【发布时间】:2020-01-04 13:37:23
【问题描述】:

我正在尝试将 df2['values'] 中的列中的值分配给 df1['values'] 列。但是,只有在以下情况下才应分配值:

  1. df2['category'] 等于 df1['category'](行属于同一类别)
  2. df1['date'] 在 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

【问题讨论】:

  • 您能否详细说明"date""date_range" 的外观、它们的类型以及它们的格式?
  • 你能展示一些示例数据吗
  • @NaturalFrequency 我已经从两个数据帧中添加了一些数据样本
  • @aws_apprentice 我已经从两个数据帧中添加了一些数据样本
  • 所以df2['date_range'] 的每一行都是一个列表?

标签: python pandas loops dataframe


【解决方案1】:

编辑:更正错误代码并添加评论中的 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 中的所有值。这将为在早期合并中与 df1 不匹配的子集值创建 NaN

因此,我们将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"] 与日期范围匹配,则必须删除一些值,否则重复会混淆解释。

【讨论】:

  • 不幸的是,我收到以下类型错误'(Int64Index([], dtype='int64'), 'values_y')' is an invalid key ,因为cond_idxpandas.core.indexes.numeric.Int64Index 类型。
  • @Audiogott 我需要查看更多解释,这不会弄乱我的索引。您使用的列名称是否与我的相同?你用的是什么版本的pandas
  • 我的pandas 版本是0.25.1。在我的情况下,列名略有不同,但是我已经相应地调整了它们,所以这应该不是问题
  • 似乎错误来自index 实际上是空的,而不是来自类型。这是因为isin 我搞砸了
  • isin 不适合这种用法,我要重写我的答案
【解决方案2】:

你可以完成第一点:

1. df2['category'] 等于 df1['category']

使用连接。

然后,您可以使用 for 循环来过滤来自 df1[date] 中的合并数据帧中未包含在 df2[date_range] 中的数据。不幸的是,我需要有关 df1[date] 和 df2[date_range] 内容的更多信息来编写可以完全做到这一点的代码。

【讨论】:

  • 虽然这将是您采用的方法的一部分,但目前这不能作为答案,请read 什么是好的答案
  • 我刚刚解释了为什么我对你投了反对票,并与一个好的答案相关联,因为 OP 没有提供样本数据,在他提供之前很难回答这个问题。您发布的答案更像是评论而不是任何东西
  • @AnaPreciado 我已经从两个数据帧中添加了一些数据样本
猜你喜欢
  • 2023-03-27
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
相关资源
最近更新 更多