我正在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)
它运作良好,但我想避免使用这么多的fors,我想欣赏任何有关如何实现这一点的建议。
答案 0 :(得分:4)
您可以改为使用where
:
for k, v in lookup.items():
df = df.where(~df.isin(v), k)
这表示当df
中未包含这些值时保留v
的值。否则,请使用值k
替换它们。分配会在每次迭代时覆盖df
以累积分类标签。
此方法适用于一个操作中的所有列,因此仅当您要将给定数值的每个实例替换为其分类编码字母时才有效。
where
还有另一个选项可指定就地修改,但不幸的是,它不能与具有混合列类型的DataFrame一起使用。在您的示例中,列0,1和2的类型为object
,其余的类型为float
。因此,pandas
保守地(并且效率低)假设它必须将所有内容转换为object
以进行就地覆盖,并引发TypeError
而不是进一步检查是否只有相同-typed列实际上受到突变的影响。
例如,这个:
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
时无法禁用此类型的安全检查。