替换 pandas DataFrame 中的列值
- 2025-01-22 08:45:00
- admin 原创
- 85
问题描述:
我正在尝试替换数据框中某一列的值。列 ('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),但不明白为什么什么都没有发生。
任何帮助都将受到感谢。
解决方案 1:
如果我理解正确的话,你想要的是这样的:
w['female'] = w['female'].map({'female': 1, 'male': 0})
(在这里,我将值转换为数字,而不是包含数字的字符串。如果您确实愿意,您可以将它们转换为"1"
和"0"
,但我不确定您为什么要这样做。)
您的代码不起作用的原因是,['female']
在列('female'
您的中的第二列w['female']['female']
)上使用并不意味着“选择值为‘female’的行”。它的意思是选择索引为‘ female’的行,而您的 DataFrame 中可能没有任何这样的行。
解决方案 2:
您可以使用 loc 编辑数据框的子集:
df.loc[<row selection>, <column selection>]
在这种情况下:
w.loc[w.female != 'female', 'female'] = 0
w.loc[w.female == 'female', 'female'] = 1
解决方案 3:
w.female.replace(to_replace=dict(female=1, male=0), inplace=True)
参见pandas.DataFrame.replace() 文档。
解决方案 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)
解决方案 7:
您也可以apply
使用.get
ie
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
如果数据框中列的所有可能值都在字典中定义,则应使用字典,否则,对于字典中未定义的值,它将为空。
解决方案 8:
w.replace({'female':{'female':1, 'male':0}}, inplace = True)
上述代码将用 1 替换“女性”,用 0 替换“男性”,仅在“女性”列中
解决方案 9:
使用Series.map
Series.fillna
如果您的列包含的字符串多于female
和male
,则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
对于正确的方法,我们map
用链接fillna
,因此我们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:
另外,对于这些类型的作业,还有一个内置函数 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)
然后,您将剩下两个新列,为您提供“女性”的虚拟编码,并且您摆脱了带有字符串的列。
解决方案 11:
pandas
中还有一个函数factorize
,您可以使用它来自动完成此类工作。它将标签转换为数字:['male', 'female', 'male'] -> [0, 1, 0]
。有关更多信息,请参阅此答案。
解决方案 12:
w.female = np.where(w.female=='female', 1, 0)
如果有人正在寻找 numpy 解决方案。这对于根据条件替换值很有用。 if 和 else 条件都是 所固有的np.where()
。如果列除了 之外还包含许多唯一值,则使用的解决方案df.replace()
可能不可行'male'
,所有这些都应替换为0
。
另一个解决方案是连续使用df.where()
and 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。因此在这种情况下,您可以使用 DataFrame 方法,例如.replace
。
当您使用.loc
或 时,iloc
您将返回 Series,而 Series 没有.replace
方法,因此您应该使用诸如apply
等map
方法。
解决方案 15:
为了更通用地回答这个问题,使其适用于更多用例,而不仅仅是 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]
这样比较起来容易多了,对吧?
解决方案 16:
如果只有两个类,则可以使用相等运算符。例如:
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