使用dict重映射pandas列中的值,如果KeyError则为None



我想修改以下数据帧df:的col1

col1        col2
0       Black       7
1       Death       2
2       Hardcore    6
3       Grindcore   1
4       Deathcore   4
...

我想使用一个名为cat_dic={'Black':'B', 'Death':'D', 'Hardcore':'H'}的dict来获得以下数据帧:

col1        col2
0       B           7
1       D           2
2       H           6
3       None        1
4       None        4
...

我知道我可以使用df.mapdf.replace,例如:

df.replace({"col1":cat_dic})

但是我希望dictionary的KeyErrors返回None,在前一行中,我得到了以下结果:

col1        col2
0       B           7
1       D           2
2       H           6
3       Grindcore   1
4       Deathcore   4
...

考虑到Grindcore和Deathcore并不是col1中唯一两个我想设置为None的值,你知道怎么做吗?

使用dict.get:

df['col1'] = df['col1'].map(lambda x: cat_dic.get(x, None))
#default value is None
df['col1'] = df['col1'].map(cat_dic.get)
print (df)
col1  col2
0     B     7
1     D     2
2     H     6
3  None     1
4  None     4

50k行的性能比较:

df = pd.concat([df] * 10000, ignore_index=True)
cat_dic={'Black':'B', 'Death':'D', 'Hardcore':'H'}
In [93]: %timeit df['col1'].map(cat_dic.get)
3.22 ms ± 16.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [94]: %timeit df.col1.apply(lambda x: None if x not in cat_dic.keys() else cat_dic[x])
15 ms ± 293 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [95]: %timeit df['col1'].replace(dict(dict.fromkeys(df['col1'].unique(), None), **cat_dic))
12.3 ms ± 409 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [96]: %timeit df.col1.apply(lambda x: None if x not in cat_dic.keys() else x)
13.8 ms ± 837 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [97]: %timeit df['col1'].map(cat_dic).replace(dict({np.nan: None}))
9.97 ms ± 1.25 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

您可以首先使用pd.apply

df.col1 = df.col1.apply(lambda x: None if x not in cat_dic.keys() else x)

然后,您可以安全地使用pd.replace

df.replace({"col1":cat_dic})

这可以在一行中完成:

df1['col1'] = df1.col1.apply(lambda x: None if x not in cat_dic.keys() else cat_dic[x])

输出为:

col1  col2
0     B     7
1     D     2
2     H     6
3  None     1
4  None     4

这里有一个简单的一行解决方案,它为我们提供了预期的输出。

df['col1'] = df['col1'].map(cat_dic).replace(dict({np.nan: None}))

输出:

col1  col2
0     B     7
1     D     2
2     H     6
3  None     1
4  None     4

Series.map已经将NaN映射到不匹配的密钥

$ print(df['col1'].map(cat_dic))
0      B
1      D
2      H
3    NaN
4    NaN
Name: col1, dtype: object

无论如何,您可以使用col1列中丢失的密钥更新cat_dic

cat_dic = dict(dict.fromkeys(df['col1'].unique(), None), **cat_dic)
df['col1'] = df['col1'].replace(cat_dic)
print(cat_dic)
{'Black': 'B', 'Death': 'D', 'Hardcore': 'H', 'Grindcore': None, 'Deathcore': None}
print(df)
col1  col2
0     B     7
1     D     2
2     H     6
3  None     1
4  None     4
In [6]: df.col1.map(cat_dic.get)
Out[6]: 
0       B
1       D
2       H
3    None
4    None
dtype: object

您也可以使用apply,两者都有效。当使用Series时,我认为map更快。


说明:

您可以通过使用dict.get而不是使用[..]-运算符来获得丢失密钥的默认值。默认情况下,此默认值为None。因此,简单地将dict.get方法传递给apply/map就可以了。

相关内容

最新更新