【问题标题】:Replacing column values in a pandas DataFrame替换 pandas DataFrame 中的列值
【发布时间】:2014-06-12 00:07:23
【问题描述】:

我正在尝试替换数据框一列中的值。列 ('female') 仅包含值 'female' 和 'male'。

我尝试了以下方法:

w['female']['female']='1'
w['female']['male']='0' 

但收到与之前结果完全相同的副本。

理想情况下,我希望得到一些类似于以下循环元素的输出。

if w['female'] =='female':
    w['female'] = '1';
else:
    w['female'] = '0';

我查看了问题文档 (http://pandas.pydata.org/pandas-docs/stable/gotchas.html),但无法弄清楚为什么什么也没发生。

任何帮助将不胜感激。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    如果我理解正确,你想要这样的东西:

    w['female'] = w['female'].map({'female': 1, 'male': 0})
    

    (这里我将值转换为数字,而不是包含数字的字符串。如果你真的想要,你可以将它们转换为"1""0",但我不确定你为什么想要那个。)

    您的代码不起作用的原因是因为在列上使用['female']w['female']['female'] 中的第二个'female')并不意味着“选择值为'女性'的行”。这意味着选择 index 为“女性”的行,您的 DataFrame 中可能没有这些行。

    【讨论】:

    • 谢谢。正是我想要的。如果我要将“女性”映射到 1,将其他任何内容映射到“0”。这将如何运作?
    • 只使用这个,如果列中的所有值都在 map 函数中给出。未在 map 函数中指定的列值将被替换为 nan。
    • 我还建议使用.loc 语法来避免SettingWithCopyWarning: pandas.pydata.org/pandas-docs/stable/…
    • 我使用 .replace 而不是 .map
    • 我如何摆脱'.'在两列或更多列上的数千个中,无法弄清楚。非常感谢
    【解决方案2】:

    您可以使用 loc 编辑数据框的子集:

    df.loc[<row selection>, <column selection>]
    

    在这种情况下:

    w.loc[w.female != 'female', 'female'] = 0
    w.loc[w.female == 'female', 'female'] = 1
    

    【讨论】:

    • 我将如何调整它,这样我就不需要通过条件选择特定的行,只需要特定列中的所有行?因此,将列中的所有单元格更改为特定值。
    • @DhruvGhulati,你会使用 df.loc[:, ]
    【解决方案3】:
    w.female.replace(to_replace=dict(female=1, male=0), inplace=True)
    

    pandas.DataFrame.replace() docs

    【讨论】:

    • 这是我遇到的问题的最佳解决方案,谢谢!
    【解决方案4】:

    轻微变化:

    w.female.replace(['male', 'female'], [1, 0], inplace=True)
    

    【讨论】:

      【解决方案5】:

      这也应该有效:

      w.female[w.female == 'female'] = 1 
      w.female[w.female == 'male']   = 0
      

      【讨论】:

        【解决方案6】:

        这是非常紧凑的:

        w['female'][w['female'] == 'female']=1
        w['female'][w['female'] == 'male']=0
        

        另一个好:

        w['female'] = w['female'].replace(regex='female', value=1)
        w['female'] = w['female'].replace(regex='male', value=0)
        

        【讨论】:

        • 第一个例子是链式索引并被警告,因为它不能保证生成的 df 是副本还是视图。见chained-indexing
        【解决方案7】:

        您也可以将apply.get 一起使用,即

        w['female'] = w['female'].apply({'male':0, 'female':1}.get):

        w = pd.DataFrame({'female':['female','male','female']})
        print(w)
        

        数据框w:

           female
        0  female
        1    male
        2  female
        

        使用apply 替换字典中的值:

        w['female'] = w['female'].apply({'male':0, 'female':1}.get)
        print(w)
        

        结果:

           female
        0       1
        1       0
        2       1 
        

        注意: apply with dictionary 如果数据框中列的所有可能值都在字典中定义,则应使用字典,否则字典中未定义的值将为空。

        【讨论】:

          【解决方案8】:

          另外还有用于这些类型分配的内置函数 pd.get_dummies:

          w['female'] = pd.get_dummies(w['female'],drop_first = True)
          

          这为您提供了一个包含两列的数据框,其中一列用于 w['female'] 中出现的每个值,您删除其中的第一列(因为您可以从剩下的那一列推断它)。新列将自动命名为您替换的字符串。

          如果您有具有两个以上可能值的分类变量,这将特别有用。此函数创建区分所有情况所需的尽可能多的虚拟变量。请注意,不要将整个数据框分配给单个列,而是,如果 w['female'] 可能是 'male'、'female' 或 'neutral',请执行以下操作:

          w = pd.concat([w, pd.get_dummies(w['female'], drop_first = True)], axis = 1])
          w.drop('female', axis = 1, inplace = True)
          

          然后,您将得到两个新列,为您提供“女性”的虚拟编码,并且您摆脱了带有字符串的列。

          【讨论】:

            【解决方案9】:

            使用Series.mapSeries.fillna

            如果您的列包含的字符串多于 femalemale,则在这种情况下,Series.map 将失败,因为它会为其他值返回 NaN

            这就是为什么我们必须用fillna链接它:

            .map 失败的示例

            df = pd.DataFrame({'female':['male', 'female', 'female', 'male', 'other', 'other']})
            
               female
            0    male
            1  female
            2  female
            3    male
            4   other
            5   other
            
            df['female'].map({'female': '1', 'male': '0'})
            
            0      0
            1      1
            2      1
            3      0
            4    NaN
            5    NaN
            Name: female, dtype: object
            

            对于正确方法,我们将mapfillna 链接在一起,因此我们用原始列中的值填充NaN

            df['female'].map({'female': '1', 'male': '0'}).fillna(df['female'])
            
            0        0
            1        1
            2        1
            3        0
            4    other
            5    other
            Name: female, dtype: object
            

            【讨论】:

              【解决方案10】:
              w.replace({'female':{'female':1, 'male':0}}, inplace = True)
              

              上面的代码会将“female”替换为1,将“male”替换为0,仅在“female”列中

              【讨论】:

              • 我实际上并没有在 OP 的情况下尝试过,但为inplace+1
              【解决方案11】:

              pandas 中还有一个名为factorize 的函数,您可以使用它来自动执行此类工作。它将标签转换为数字:['male', 'female', 'male'] -&gt; [0, 1, 0]。有关更多信息,请参阅this 答案。

              【讨论】:

                【解决方案12】:
                w.female = np.where(w.female=='female', 1, 0)
                

                如果有人正在寻找 numpy 解决方案。这对于根据条件替换值很有用。 if 和 else 条件都是 np.where() 所固有的。如果该列除了'male' 之外还包含许多唯一值,则使用df.replace() 的解决方案可能不可行,所有这些值都应替换为0

                另一种解决方案是连续使用df.where()df.mask()。这是因为它们都没有实现 else 条件。

                w.female.where(w.female=='female', 0, inplace=True) # replace where condition is False
                w.female.mask(w.female=='female', 1, inplace=True) # replace where condition is True
                

                【讨论】:

                  【解决方案13】:
                  dic = {'female':1, 'male':0}
                  w['female'] = w['female'].replace(dic)
                  

                  .replace 有一个字典作为参数,您可以在其中更改并执行您想要或需要的任何操作。

                  【讨论】:

                    【解决方案14】:

                    我认为在回答中应该指出你在上面建议的所有方法中得到了哪种类型的对象:它是 Series 还是 DataFrame。

                    当您通过w.female.w[[2]](假设2 是您的列号)获得列时,您将返回DataFrame。 因此,在这种情况下,您可以使用像 .replace 这样的 DataFrame 方法。

                    当你使用.lociloc时你会返回Series,而Series没有.replace方法,所以你应该使用applymap等方法。

                    【讨论】:

                      【解决方案15】:

                      要更笼统地回答这个问题,使其适用于更多用例,而不仅仅是 OP 所要求的,请考虑使用此解决方案。我使用jfs's solution 解决方案来帮助我。在这里,我们创建了两个相互帮助的函数,无论您是否知道确切的替换,都可以使用它们。

                      import numpy as np
                      import pandas as pd
                      
                      
                      class Utility:
                      
                          @staticmethod
                          def rename_values_in_column(column: pd.Series, name_changes: dict = None) -> pd.Series:
                              """
                              Renames the distinct names in a column. If no dictionary is provided for the exact name changes, it will default
                              to <column_name>_count. Ex. female_1, female_2, etc.
                      
                              :param column: The column in your dataframe you would like to alter.
                              :param name_changes: A dictionary of the old values to the new values you would like to change.
                              Ex. {1234: "User A"} This would change all occurrences of 1234 to the string "User A" and leave the other values as they were.
                              By default, this is an empty dictionary.
                              :return: The same column with the replaced values
                              """
                              name_changes = name_changes if name_changes else {}
                              new_column = column.replace(to_replace=name_changes)
                              return new_column
                      
                          @staticmethod
                          def create_unique_values_for_column(column: pd.Series, except_values: list = None) -> dict:
                              """
                              Creates a dictionary where the key is the existing column item and the value is the new item to replace it.
                              The returned dictionary can then be passed the pandas rename function to rename all the distinct values in a
                              column.
                              Ex. column ["statement"]["I", "am", "old"] would return
                              {"I": "statement_1", "am": "statement_2", "old": "statement_3"}
                      
                              If you would like a value to remain the same, enter the values you would like to stay in the except_values.
                              Ex. except_values = ["I", "am"]
                              column ["statement"]["I", "am", "old"] would return
                              {"old", "statement_3"}
                      
                              :param column: A pandas Series for the column with the values to replace.
                              :param except_values: A list of values you do not want to have changed.
                              :return: A dictionary that maps the old values their respective new values.
                              """
                              except_values = except_values if except_values else []
                              column_name = column.name
                              distinct_values = np.unique(column)
                              name_mappings = {}
                              count = 1
                              for value in distinct_values:
                                  if value not in except_values:
                                      name_mappings[value] = f"{column_name}_{count}"
                                      count += 1
                              return name_mappings
                      

                      对于OP的用例,只要使用就足够简单了

                      w["female"] = Utility.rename_values_in_column(w["female"], name_changes = {"female": 0, "male":1}
                      

                      但是,要知道您可能想要重命名的数据框中的所有不同唯一值并不总是那么容易。就我而言,列的字符串值是散列值,因此它们会损害可读性。由于create_unique_values_for_column 函数,我所做的是用更易读的字符串替换那些散列值。

                      df["user"] = Utility.rename_values_in_column(
                          df["user"],
                          Utility.create_unique_values_for_column(df["user"])
                      )
                      

                      这会将我的用户列值从 ["1a2b3c", "a12b3c","1a2b3c"] 更改为 ["user_1", "user_2", "user_1]。更容易比较,对吧?

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2019-08-15
                        • 2019-07-16
                        • 1970-01-01
                        • 2013-09-12
                        • 1970-01-01
                        相关资源
                        最近更新 更多