替换pandas数据框架中的列值

我试图替换一个数据框架的一列的值。列('female')只包含值'female'和'male'。

我尝试过以下方法:

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

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

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

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

我已经查看了gotchas文档(http://pandas.pydata.org/pandas-docs/stable/gotchas.html),但不明白为什么什么都没有发生。

任何帮助都将不胜感激。

694833 次浏览

如果我没理解错的话,你想要这样的东西:

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

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

你的代码不能工作的原因是因为在列上使用['female'](你的w['female']['female']中的第二个'female')并不意味着“选择值为‘female’的行”。它意味着选择指数为“female”的行,其中可能在你的DataFrame中没有。

你可以使用loc编辑一个数据帧的子集:

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

在这种情况下:

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

看到pandas.DataFrame.replace()文档

轻微的变化:

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

这也可以工作:

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

还有一个内置函数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)

然后你剩下两个新的列,给你'female'的虚拟编码,你去掉了带字符串的列。

pandas中还有一个名为factorize的函数,你可以使用它自动完成这种类型的工作。它将标签转换为数字:['male', 'female', 'male'] -> [0, 1, 0]。更多信息见答案。

你也可以将apply.get一起使用。

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

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

Dataframe 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应该被使用,如果数据帧中所有可能的列的值都定义在字典else中,对于字典中没有定义的列,它将为空。

这非常紧凑:

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)

我认为,在答案应该指出哪种类型的对象,你得到的所有方法上面建议:它是系列或数据帧。

当你通过w.female.w[[2]]获取列时(其中,假设2是你的列的编号),你会得到DataFrame。 所以在这种情况下,你可以使用像.replace.

这样的DataFrame方法

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

使用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
dic = {'female':1, 'male':0}
w['female'] = w['female'].replace(dic)

.replace有一个字典作为参数,在这个字典中你可以做任何你想要或需要的事情。

w.replace({'female':{'female':1, 'male':0}}, inplace = True)

上面的代码将把'female'替换为1,'male'替换为0,仅在'female'列中

w.female = np.where(w.female=='female', 1, 0)

如果有人在寻找一个麻木的解决方案。这对于基于条件替换值非常有用。if和else条件都是np.where()中固有的。使用df.replace()的解决方案可能是不可行的,如果该列除了'male'之外还包含许多唯一的值,所有这些值都应该被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

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

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]。比较起来容易多了,对吧?

如果你只有两个类,你可以使用相等运算符。例如:

df = pd.DataFrame({'col1':['a', 'a', 'a', 'b']})


df['col1'].eq('a').astype(int)
# (df['col1'] == 'a').astype(int)

输出:

0    1
1    1
2    1
3    0
Name: col1, dtype: int64

W ['female'] = np。其中(w['female'] == "male", 0,1)