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