我正在用 python 编写一个程序来替换数据框的一些值,我的想法是我有一个名为 file.txt 的文件,看起来像这样:
A:s:Y:0.1:0.1:0.1:0.2:0.1
B:r:D:0.3:0.5:0.1:0.2:0.2
C:f:C:0.3:0.4:0.2:-0.1:0.4
D:f:C:0.1:0.2:0.1:0.1:0.1
F:f:C:0.1:-0.1:-0.1:0.1:0.1
G:f:C:0.0:-0.1:0.1:0.3:0.4
H:M:D:0.1:0.4:0.1:0.0:0.4
我想使用 ':::' 作为分隔符,我想按照以下规则为某些字符串替换四列的值:
所有属于 range1 的值都将被替换为“N”:
range1=[-0.2,-0.1,0,0.1,0.2] -> 'N'
所有属于 range2 的值都将被替换为“L”:
range2=[-0.5,-0.4,-0.3] -> 'L'
所有属于 range3 的值都将被替换为“H”:
range3=[0.3,0.4,0.5]
为了实现这一点,我尝试了以下方法:
import pandas as pd
df= pd.read_csv('file.txt', sep=':',header=None)
labels=df[3]
range1=[-0.2,-0.1,0,0.1,0.2]
range2=[-0.5,-0.4,-0.3]
range3=[0.3,0.4,0.5]
lookup = {'N': range1, 'L': range2, 'H': range3}
for k, v in lookup.items():
df.loc[df[3].isin(v), 3] = k
for k, v in lookup.items():
df.loc[df[4].isin(v), 4] = k
for k, v in lookup.items():
df.loc[df[5].isin(v), 5] = k
for k, v in lookup.items():
df.loc[df[6].isin(v), 6] = k
for k, v in lookup.items():
df.loc[df[7].isin(v), 7] = k
print(df)
它工作得很好,但我想避免使用这么多 for,我想感谢任何关于如何实现这一目标的建议。
最佳答案
您可以使用 where
代替:
for k, v in lookup.items():
df = df.where(~df.isin(v), k)
这表示在 v
中不包含 df
的值时保留这些值。否则,将它们替换为值 k
。分配在每次迭代时覆盖 df
以累积分类标签。
此方法适用于一次操作中的所有列,因此仅当您想用其分类编码字母替换给定数值的每个实例时才适用。
where
有另一个选项指定就地修改,但不幸的是它不能与具有混合列类型的 DataFrame 一起使用。在您的示例中,第 0、1 和 2 列的类型为 object
,而其余列的类型为 float
。因此,pandas
保守地(并且效率低下)假设它必须将所有内容转换为 object
以进行就地覆盖,并引发 TypeError
而不是进一步检查以查看是否只有相同类型的列实际上受到了突变的影响。
例如,这个:
df.where(~df.isin(v), k, inplace=True)
将引发 TypeError
。
Pandas 的这种限制相当令人沮丧。例如,您也不能使用常规的 pandas 赋值来解决它,因为下面也会给出相同的 TypeError
:
for k, v in lookup.items():
df.where(~df.isin(v), inplace=True)
df[df.isnull()] = k # <-- same TypeError
并且令人惊奇地将 try_cast
关键字参数设置为 True
和/或将 raise_on_error
关键字参数设置为 False
不影响是否引发 TypeError
,因此您不能在使用 where
时禁用此类型安全检查。
关于python - 如何优化以下代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36723702/