使用.loc在索引不同但长度相等的Series间赋值的问题
解决Series赋值时的索引匹配问题
这个问题的核心是pandas在赋值时会严格按索引对齐,而不是按你选中行的顺序来赋值。你选中的df.name == 'a'的行索引是[0,2],但vals_a的索引是[0,1]——pandas只会把vals_a中索引0的值给到df的0行,索引1的值找不到df中对应索引的行(df的1行不是name='a'),所以df的2行就只能填充NaN;同理vals_b的索引1对应df的1行,所以df的1行得到54,3行因为没有对应索引的值变成NaN。
下面给你几种可行的解决方案,适配不同的场景:
方案1:直接按顺序赋值(忽略索引)
如果你的vals_a和vals_b的顺序和df中筛选出的行顺序完全一致,最简单的方法是取Series的values属性(这会把它转换成numpy数组,不携带索引信息),这样pandas就会按顺序把值赋给筛选出的行:
import pandas as pd df = pd.DataFrame({'name': ['a', 'b', 'a', 'b'], 'num': [1, 1, 2, 2], 'val': None}) vals_a = pd.Series([21,32]) vals_b = pd.Series([43,54]) df.loc[df.name == 'a', 'vals'] = vals_a.values df.loc[df.name == 'b', 'vals'] = vals_b.values
执行后就能得到你想要的结果:
name num val vals 0 a 1 None 21.0 1 b 1 None 43.0 2 a 2 None 32.0 3 b 2 None 54.0
方案2:通过关联键映射(更稳妥,适合复杂场景)
如果实际场景中vals_a/vals_b的顺序不一定和筛选行的顺序对应,但它们和num列是一一对应的(比如num=1对应第一个值,num=2对应第二个值),推荐用映射或合并的方式,避免索引带来的问题:
子方案2.1:用字典映射+apply
先把name、num和vals的对应关系整理成字典,再通过apply逐行匹配:
# 构建name -> (num: vals)的映射 vals_mapping = { 'a': {1:21, 2:32}, 'b': {1:43, 2:54} } df['vals'] = df.apply(lambda row: vals_mapping[row['name']][row['num']], axis=1)
子方案2.2:合并小DataFrame
如果你的vals来自另一个DataFrame的切片,更清晰的方式是把vals整理成带关联键(name和num)的小DataFrame,再和原df合并:
# 模拟从其他DataFrame切片得到的vals数据 vals_df = pd.DataFrame({ 'name': ['a','a','b','b'], 'num': [1,2,1,2], 'vals': [21,32,43,54] }) # 按name和num合并,保留原df的所有行 df = df.merge(vals_df, on=['name','num'], how='left')
这种方法的优势是逻辑清晰,不容易出错,尤其适合数据量较大或关联条件复杂的场景。
内容的提问来源于stack exchange,提问作者Cilantro Ditrek
相关产品推荐
相关产品推荐

