Pyhton Pandas 将列名称系列映射到字典并处理缺失值



我想将map函数应用于数据帧的列,如下所示:

d = {'one': [1, 2], 'two': [3, 4], 'three':[3,3]}
df = pd.DataFrame(data=d)
recodes = {'one':'A', 'two':'B'}
c = df.columns.map(recodes)
c
#result: Index(['A', 'B', nan], dtype='object')

都很好

现在我想应用另一种字典,值是元组:

recodes2 = {'one':('A','H'), 'two':('AB','HB')}
c = df.columns.map(recodes2)
c

这是行不通的。错误是:

TypeError: Expected tuple, got float

预期输出:

MultiIndex([(       'A',        'H'),
(      'AB',       'HB'),
('_unknown', '_unknown')],
)

问题是蹦跶:

  • 一方面为什么会这样? 为什么我没有得到(nan,nan)自动默认值。
  • 其次如何避免这个问题
  • 以及如何包含一种默认值,例如,对于不属于字典一部分的值,例如元组("_unknown","_unknown")。
  • 我寻找一种比获取列的值集更pythonic的答案,并修改字典以包含字典中最初不存在的所有键的默认值。

一个可能的解决方案是:

d = {'one': [1, 2], 'two': [3, 4],'three':[6,7],'four':[8,9]}
df = pd.DataFrame(data=d)
# original recodes dict
recodes3 = {'one':('one','A','H'), 'two':('two','AB','HB')}
# complete recodes dict
missing_values = [col for col in df.columns if col not in recodes3.keys()]
print(missing_values)
recodes_missing = {k:(k,'_unknown','_unknown') for k in missing_values}
#complete the recode dict:
recodes4 = {**recodes3,**recodes_missing}
print(recodes4)
c = df.columns.map(recodes4)
c

但是应该有一种方法可以处理地图熊猫地图函数中的缺失值(我猜)

第一个问题

为什么我没有得到(nan,nan)自动默认值。

该函数Index.map(mapper, na_action=None)。对于值在dict中不作为键存在时的默认行为,请比较pd.Series.map的文档:

arg[即Index.map] 中的== mapper是一个字典,序列中不在字典中的值(作为键)将转换为NaN

因此,这正是该函数的作用:将缺少的键转换为NaN值。它不"关心"其他键是否转换为tuples或任何其他类型。随后,当python尝试运行MultiIndex.from_tuples(new_values, names=names)时,您会遇到更远的错误,而new_values看起来像[('A','H'), ('AB','HB'), np.nan]

第二个和第三个问题

[H]如何避免此问题

[H]如何包含一种默认值

让我们把这两者放在一起,因为避免这个问题的方法确实包括提供一个默认值(各种)。这里有三个选项。第三个是map的替代品。

  • 选项 1

不使用df.columns.map(recodes2),创建一个 lambda 函数,并应用dict.get,如果dict缺少键,则允许传递默认值:

c = df.columns.map(lambda x: recodes2.get(x,("_unknown","_unknown")))
c
MultiIndex([(       'A',        'H'),
(      'AB',       'HB'),
('_unknown', '_unknown')],
)
  • 选项 2

不使用常规dict,而是使用defaultdict。这个类似字典的对象将缺少的键添加到dict(如果缺少默认值),然后该值在map中使用。例如,我们可以执行以下操作:

from collections import defaultdict
recodes2 = {'one':('A','H'), 'two':('AB','HB')}
def def_value():
return ("_unknown","_unknown")
# create `defaultdict` and add `update` with `recodes2` 
my_def_dict = defaultdict(def_value)
my_def_dict.update(recodes2)
print(my_def_dict)
defaultdict(<function def_value at 0x000001F1050F0CA0>, 
{'one': ('A', 'H'), 
'two': ('AB', 'HB')})
c = df.columns.map(my_def_dict)
print(c)
MultiIndex([(       'A',        'H'),
(      'AB',       'HB'),
('_unknown', '_unknown')],
)
# note that we have now added the key to the dict as well! May be useful, may not be
print(my_def_dict)
defaultdict(<function def_value at 0x000001F105124280>, 
{'one': ('A', 'H'), 
'two': ('AB', 'HB'), 
'three': ('_unknown', '_unknown')})
  • 选项 3

除了依赖map,我们也可以只在tupleslist上使用pd.MultiIndex.from_tuples,用列表推导创建。这样做的好处是我们可以增加准默认值(或:存根名称;例如f'_unknown_{int}'),以便您最终也会为dict中不存在的值提供唯一的列名。例如:

# let's add another value, `four` to `df.columns`
d = {'one': [1, 2], 'two': [3, 4], 'three':[3,3], 'four':[4,4]}
df = pd.DataFrame(data=d)
# create a list from which to `pop` the first value consecutively
ints = list(np.repeat([*range(1, len(df.columns)+1)],2))
# [1, 1, 2, 2, 3, 3, 4, 4]
# use list comprehension inside `MultiIndex.from_tuples`
c = pd.MultiIndex.from_tuples([recodes2[col] 
if col in recodes2 
else (f'_unknown_{ints.pop(0)}',
f'_unknown_{ints.pop(0)}') 
for col in df.columns])
c
MultiIndex([(         'A',          'H'),
(        'AB',         'HB'),
('_unknown_1', '_unknown_1'),
('_unknown_2', '_unknown_2')],
)

相关内容

  • 没有找到相关文章

最新更新