如何在DataFrame中将重复字符串与字典值正确关联匹配?
问题解决:DataFrame多层索引中重复字符串与数字的顺序映射
问题背景
在将数字列表与字符串列表关联到多层索引的Pandas Series时,因字符串列表存在重复值,导致重复的字符串总是匹配到最后一个对应数字,无法实现第一个重复字符串对应第一个数字、第二个对应第二个数字的需求。
原代码
import pandas as pd categories = {"key1":["string1", "string2", "string3"], "key2": ["string1", "str1", "str2"]} strings= ["string1", "string2", "string3", "string1", "str1", "str2"] numbers = [1,2,3,4,5,6] array = [] expected_fields = [] #创建具有双层行索引的DataFrame,第一层为categories的键,第二层为其值列表中的元素 for key, value in categories.items(): array.extend([key]* len(value)) expected_fields.extend(value) arrays = [array ,expected_fields] #创建DataFrame tuples = list(zip(*arrays)) index = pd.MultiIndex.from_tuples(tuples) df = pd.Series(dtype='float', index=index) for key, values in categories.items(): for value in values: for i in range(len(strings)): if strings[i] == value: df[key, value] = numbers[i] print(df)
当前输出
key1 string1 4.0 <--------- string2 2.0 string3 3.0 key2 string1 4.0 str1 5.0 str2 6.0
期望输出
key1 string1 1.0 <--------- string2 2.0 string3 3.0 key2 string1 4.0 str1 5.0 str2 6.0
解决方案
核心思路
原循环的问题是每次匹配到相同字符串时都会覆盖之前的值,最后保留的是最后一次匹配的数字。要实现按顺序匹配,需要跟踪每个字符串已匹配的次数,每次匹配时只取未被使用过的对应数字。
修改后的代码
import pandas as pd categories = {"key1":["string1", "string2", "string3"], "key2": ["string1", "str1", "str2"]} strings= ["string1", "string2", "string3", "string1", "str1", "str2"] numbers = [1,2,3,4,5,6] # 先创建字符串到对应数字的映射,按出现顺序记录每个字符串的数字列表 str_num_map = {} for s, n in zip(strings, numbers): if s not in str_num_map: str_num_map[s] = [] str_num_map[s].append(n) # 创建多层索引的Series array = [] expected_fields = [] for key, value in categories.items(): array.extend([key]* len(value)) expected_fields.extend(value) tuples = list(zip(array, expected_fields)) index = pd.MultiIndex.from_tuples(tuples) df = pd.Series(dtype='float', index=index) # 遍历categories,按顺序取出对应数字 for key, values in categories.items(): for value in values: # 取出当前字符串的第一个数字,并从列表中移除,确保下一次取的是下一个 df[key, value] = str_num_map[value].pop(0) print(df)
代码说明
- 首先通过
zip(strings, numbers)遍历,为每个字符串创建一个数字列表,按顺序存储所有对应数字。比如string1对应的列表就是[1,4]。 - 在填充Series时,每次取出对应字符串列表的第一个数字,然后用
pop(0)移除该数字,这样后续再次遇到该字符串时,就会取下一个未使用的数字。 - 这个方法不需要统计categories各键的元素数量,完全基于字符串的出现顺序来匹配数字,符合需求。
内容的提问来源于stack exchange,提问作者saul santos
相关产品推荐
相关产品推荐

