Python 使用dict重新映射列中的值
我有一本这样的字典:Python 使用dict重新映射列中的值,python,dictionary,pandas,remap,Python,Dictionary,Pandas,Remap,我有一本这样的字典:di={1:a',2:B} 我想将其应用于数据帧的“col1”列,类似于: col1 col2 0 w a 1 1 2 2 2 NaN 要获得: col1 col2 0 w a 1 A 2 2 B NaN 我怎样才能做到最好?出于某种原因,谷歌搜索与此相关的术语只会向我显示有关如何从dicts生成列的链接,反之亦然:-/你
di={1:a',2:B}
我想将其应用于数据帧的“col1”列,类似于:
col1 col2
0 w a
1 1 2
2 2 NaN
要获得:
col1 col2
0 w a
1 A 2
2 B NaN
我怎样才能做到最好?出于某种原因,谷歌搜索与此相关的术语只会向我显示有关如何从dicts生成列的链接,反之亦然:-/你的问题有点模棱两可。至少有三种和两种解释:
di
中的键指的是索引值di
中的键指的是df['col1']
值di
中的键指的是索引位置(不是OP的问题,而是为了好玩而抛出的。)案例1: 如果
di
的键是指索引值,则可以使用update
方法:
df['col1'].update(pd.Series(di))
比如说,
import pandas as pd
import numpy as np
df = pd.DataFrame({'col1':['w', 10, 20],
'col2': ['a', 30, np.nan]},
index=[1,2,0])
# col1 col2
# 1 w a
# 2 10 30
# 0 20 NaN
di = {0: "A", 2: "B"}
# The value at the 0-index is mapped to 'A', the value at the 2-index is mapped to 'B'
df['col1'].update(pd.Series(di))
print(df)
屈服
col1 col2
1 w a
2 B 30
0 A NaN
col1 col2
1 w a
2 A 30
0 B NaN
col1 col2
1 A a
2 10 30
0 B NaN
我已经修改了您原始帖子中的值,以便更清楚地了解update
正在做什么。
注意di
中的键如何与索引值关联。索引值的顺序——即索引位置——并不重要
案例2: 如果
di
中的键指的是df['col1']
值,则@DanAllan和@DSM说明了如何通过替换实现这一点:
import pandas as pd
import numpy as np
df = pd.DataFrame({'col1':['w', 10, 20],
'col2': ['a', 30, np.nan]},
index=[1,2,0])
print(df)
# col1 col2
# 1 w a
# 2 10 30
# 0 20 NaN
di = {10: "A", 20: "B"}
# The values 10 and 20 are replaced by 'A' and 'B'
df['col1'].replace(di, inplace=True)
print(df)
屈服
col1 col2
1 w a
2 B 30
0 A NaN
col1 col2
1 w a
2 A 30
0 B NaN
col1 col2
1 A a
2 10 30
0 B NaN
注意在这种情况下,di
中的键是如何更改的,以匹配df['col1']
中的值
案例3:
如果di
中的键指向索引位置,则可以使用
df['col1'].put(di.keys(), di.values())
自
屈服
col1 col2
1 w a
2 B 30
0 A NaN
col1 col2
1 w a
2 A 30
0 B NaN
col1 col2
1 A a
2 10 30
0 B NaN
在这里,第一行和第三行被更改,因为di
中的键是0
和2
,它们与Python基于0的索引一起引用第一和第三个位置。您可以使用。例如:
>>> df = pd.DataFrame({'col2': {0: 'a', 1: 2, 2: np.nan}, 'col1': {0: 'w', 1: 1, 2: 2}})
>>> di = {1: "A", 2: "B"}
>>> df
col1 col2
0 w a
1 1 2
2 2 NaN
>>> df.replace({"col1": di})
col1 col2
0 w a
1 A 2
2 B NaN
或者直接在地图上,即df[“col1”].replace(di,inplace=True)
map
比replace
快得多
如果您的词典有多个键,那么使用map
比replace
快得多。此方法有两种版本,具体取决于您的字典是否详尽地映射了所有可能的值(以及是否希望非匹配项保留其值或转换为NAN):
穷举映射
在这种情况下,形式非常简单:
df['col1'].map(di) # note: if the dictionary does not exhaustively map all
# entries then non-matched entries are changed to NaNs
虽然map
最常用的参数是函数,但也可以使用字典或系列:
非穷举映射
如果您有一个非穷举映射,并且希望保留非匹配的现有变量,则可以添加fillna
:
df['col1'].map(di).fillna(df['col1'])
正如@jpp在这里的回答:
基准
在0.23.1版中使用以下数据:
di = {1: "A", 2: "B", 3: "C", 4: "D", 5: "E", 6: "F", 7: "G", 8: "H" }
df = pd.DataFrame({ 'col1': np.random.choice( range(1,9), 100000 ) })
使用%timeit
进行测试时,map
似乎比replace
快10倍左右
请注意,map
的加速比将随数据而变化。最大的加速似乎是使用大型词典和详尽的替换。有关更广泛的基准测试和讨论,请参见@jpp answer(上面链接)。如果您在数据帧中有多个列要重新映射,请添加此问题:
def remap(data,dict_labels):
"""
This function take in a dictionnary of labels : dict_labels
and replace the values (previously labelencode) into the string.
ex: dict_labels = {{'col1':{1:'A',2:'B'}}
"""
for field,values in dict_labels.items():
print("I am remapping %s"%field)
data.replace({field:values},inplace=True)
print("DONE")
return data
希望它能对别人有用
Cheers一种更为自然的方法是应用替换函数,如下所示:
def multiple_replace(dict, text):
# Create a regular expression from the dictionary keys
regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
# For each match, look-up corresponding value in dictionary
return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
定义函数后,可以将其应用于数据帧
di = {1: "A", 2: "B"}
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1)
DSM给出了公认的答案,但编码似乎并不适用于所有人。以下是一个适用于当前版本的pandas(自2018年8月起为0.23.4):
您将看到它看起来像:
col1 col2 converted_column
0 1 negative -1
1 2 positive 1
2 2 neutral 0
3 3 neutral 0
4 1 positive 1
适用于。或do的文档:
df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
演示:
一个很好的完整解决方案,可以保留类标签的映射:
labels = features['col1'].unique()
labels_dict = dict(zip(labels, range(len(labels))))
features = features.replace({"col1": labels_dict})
通过这种方式,您可以随时参考labels_dict.中的原始类标签,作为Nico Coalier(应用于多列)和U10 Forward(使用应用样式的方法)提出的扩展,并将其总结为一行,我建议:
df.loc[:,['col1','col2']].transform(lambda x:x.map(lambda x:{1:A',2:B}.get(x,x))
.transform()
将每个列作为一个系列进行处理。与在数据帧中传递聚合列的.apply()
相反
因此,您可以应用Series方法map()
最后,由于U10,我发现了这种行为,您可以在.get()表达式中使用整个序列。除非我误解了它的行为,它按顺序处理序列而不是按位处理。
.get(x,x)
解释了您在映射字典中没有提到的值,这些值将被.map()
方法视为Nan,否则给定的map
比替换更快(@JohnE的解决方案)如果要将特定值映射到NaN
,则需要小心使用非穷举映射。在这种情况下,正确的方法要求在时对序列进行屏蔽。填充na
,否则将撤消到NaN
的映射
import pandas as pd
import numpy as np
d = {'m': 'Male', 'f': 'Female', 'missing': np.NaN}
df = pd.DataFrame({'gender': ['m', 'f', 'missing', 'Male', 'U']})
同样好,也许是一个更好的词来描述这里发生的事情。OP发布的目标数据框不是消除了歧义吗?不过,这个答案很有用,所以+1。@DSM:Oops,你是对的,不可能出现Case3,但我不认为OP的目标数据框区分Case1和Case2,因为索引值等于列val与其他许多帖子一样,@DSM的方法不幸对我不起作用,但@unutbu的案例1确实起作用。update()
与replace()相比似乎有点笨拙
,但至少它是有效的。这个答案的最后一段代码肯定不是最优雅的,但这个答案值得称赞。对于大型词典来说,它的速度要快几个数量级,而且不使用u