首页 > 解决方案 > 根据特定列的条件将一组行的数据框值分配给另一组行

问题描述

我正在尝试根据条件将某些特定列的行的 df 值分配给其他行。
当我执行以下操作时,它会起作用,因为作业双方的第 2 级或同等以下的周数是相同的。

data = {'year': [2020,2020,2020,2020,2021,2021,2021],
'id':[1,1,1,1,1,1,1],
'week': [1,2,3,4,1,2,4],
'value':[0.1,0.2,0.3,0.4,0.5,0.6,0.7]}
df = pd.DataFrame(data)
df


      year id  week value
0   2020    1   1   0.1
1   2020    1   2   0.2
2   2020    1   3   0.3
3   2020    1   4   0.4
4   2021    1   1   0.5
5   2021    1   2   0.6
6   2021    1   4   0.7

任务:

df.loc[(df['year'] == 2021) & (df['week']<= 2),'value'] = df.loc[(df['year'] == 2020) & (df['week']<= 2),'value'].to_numpy()
df

结果:

    year    id  week value
0   2020    1   1   0.1
1   2020    1   2   0.2
2   2020    1   3   0.3
3   2020    1   4   0.4
4   2021    1   1   0.1
5   2021    1   2   0.2
6   2021    1   4   0.7

但是,当我将作业更改为第 2 周以上时,它将不起作用,因为双方的大小不相等:

df.loc[(df['year'] == 2021) & (df['week']>= 2),'value'] = df.loc[(df['year'] == 2020) & (df['week']>= 2),'value'].to_numpy()
df 

ValueError:使用可迭代设置时必须具有相等的 len 键和值

我试图在没有 .to_numpy() 的情况下做到这一点,但后来我得到了 2021 年的 NaN。

编辑:当我在没有 .to_numpy() 的情况下使用时,我得到的是:

df.loc[(df['year'] == 2021) & (df['week']<= 2),'value'] = df.loc[(df['year'] == 2020) & (df['week']<= 2),'value']
df

    year   id week value
0   2020    1   1   0.1
1   2020    1   2   0.2
2   2020    1   3   0.3
3   2020    1   4   0.4
4   2021    1   1   NaN
5   2021    1   2   NaN
6   2021    1   4   0.7

在这种情况下,2021 年的第 1 周和第 2 周不应获得 NaN。

虽然这里的手动解决方案是“简单的”,而且我不能使用有问题的几周,但它是不可扩展的,我无法在包含数万条记录的主 df 中使用它。

注意 - 此示例中缺少的周数是针对 2021 周的,因此针对分配目的地,但是缺少的周数也可能在 2020 年,因此解决方案也必须回答这种情况

当我尝试做这样的分配并只分配双方现有的周时,忽略这些缺失周的最有效方法是什么?

标签: pythonpandas

解决方案


基于索引的第一次尝试:

  1. 设置["year", "id", "week"]为数据框的索引:
>>> df = df.set_index(["year", "id", "week"])
>>> df
              value
year id week
2020 1  1       0.1
        2       0.2
        3       0.3
        4       0.4
2021 1  1       0.5  # change to 0.1
        2       0.6  # change to 0.2
        4       0.7
  1. 选择数据框的子集作为新值:
>>> vals = df.loc[pd.IndexSlice[2020, :, range(3)]]
>>> vals
              value
year id week
2020 1  1       0.1
        2       0.2
  1. 修改新值索引(2020 → 2021)
>>> vals.index = vals.index.set_levels([2021], level="year")
>>> vals
              value
year id week
2021 1  1       0.1
        2       0.2
  1. 使用新值更新您的数据框
>>> df.update(vals)
>>> df
              value
year id week
2020 1  1       0.1
        2       0.2
        3       0.3
        4       0.4
2021 1  1       0.1  # changed from 0.5
        2       0.2  # changed from 0.6
        4       0.7

对于week >= 2

>>> df = df.set_index(["year", "id", "week"])
>>> vals = df.loc[pd.IndexSlice[2020, :, range(2, 10)]]
>>> vals.index = vals.index.set_levels([2021], level="year")
>>> df.update(vals)
>>> df
              value
year id week
2020 1  1       0.1
        2       0.2
        3       0.3
        4       0.4
2021 1  1       0.5
        2       0.2  # changed from 0.6
        4       0.4  # changed from 0.7

更新:使用df.query而不是df.loc

代替:

>>> df = df.loc[pd.IndexSlice[2020, :, range(3)]]
>>> df.loc[pd.IndexSlice[2020, :, range(2, 10)]]

经过:

>>> df.query("(year == 2020) and (week <= 2)")
>>> df.query("(year == 2020) and (week >= 2)")

它更直观!


推荐阅读