python - 根据特定列的条件将一组行的数据框值分配给另一组行
问题描述
我正在尝试根据条件将某些特定列的行的 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 年,因此解决方案也必须回答这种情况
当我尝试做这样的分配并只分配双方现有的周时,忽略这些缺失周的最有效方法是什么?
解决方案
基于索引的第一次尝试:
- 设置
["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
- 选择数据框的子集作为新值:
>>> vals = df.loc[pd.IndexSlice[2020, :, range(3)]]
>>> vals
value
year id week
2020 1 1 0.1
2 0.2
- 修改新值索引(2020 → 2021)
>>> vals.index = vals.index.set_levels([2021], level="year")
>>> vals
value
year id week
2021 1 1 0.1
2 0.2
- 使用新值更新您的数据框
>>> 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)")
它更直观!
推荐阅读
- angular - 我的 Angular 8 应用程序在 IE 浏览器中显示空白页面
- r - 没有名为“外国”的包裹
- sql - T-SQL - 获取每个 ID 的最后 30 行
- react-native - React Native Bottom Tab Navigator - 图标不显示
- oracle - 加载 csv 并写入带有个别错误的不良记录
- html - 在自身上添加背景图像?
- android - 在设置中进行选择时播放声音(Android 应用程序)
- android - Flutter由于源代码错误无法编译
- java - Intellij IDEA 在调试时获取远程日志
- node.js - 在对象中传递表单数据 | 爱讯