我正在研究包含数值列以及字符串列(dtype是object
)的pandas DataFrame,并希望删除包含相对于列内分布的离群值的行。换句话说,检测每列中的异常值并删除相应的行。
我已经找到了两个解决方案,但都没有考虑到我的df不只包含数字,因此它们都会导致错误(当遇到字符串时,我假设)。
方式1:
from scipy import stats
df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
返回TypeError: unsupported operand type(s) for /: 'str' and 'int'
。这就是为什么我猜错误是由df混合了dtypes引起的。
方式2:
for col in df.columns:
lower = df[col].quantile(0.05)
upper = df[col].quantile(0.95)
df = df[col].clip(lower=lower, upper=upper)
返回KeyError
:
File omissis, in Class.remove_outliers(self, df)
423 def remove_outliers(self, df):
424 for col in df.columns:
--> 425 lower = df[col].quantile(0.05)
426 upper = df[col].quantile(0.95)
427 df = df[col].clip(lower=lower, upper=upper)
File omissis, in Series.__getitem__(self, key)
955 return self._values[key]
957 elif key_is_scalar:
--> 958 return self._get_value(key)
960 if is_hashable(key):
961 # Otherwise index.get_value will raise InvalidIndexError
962 try:
963 # For labels that don't resolve as scalars like tuples and frozensets
File omissis, in Series._get_value(self, label, takeable)
1066 return self._values[label]
1068 # Similar to Index.get_value, but we do not fall back to positional
-> 1069 loc = self.index.get_loc(label)
1070 return self.index._get_values_for_loc(self, loc, label)
File omissis, in RangeIndex.get_loc(self, key, method, tolerance)
387 raise KeyError(key) from err
388 self._check_indexing_error(key)
--> 389 raise KeyError(key)
390 return super().get_loc(key, method=method, tolerance=tolerance)
KeyError: 'colname'
你怎么解决这个问题?
编辑:这个想法是跳过非数字列,忽略它们。
我会把这个问题分成几个阶段:
首先,确定要进行离群值删除的(数字)列。参考
newdf = df.select_dtypes(include=np.number)
现在在newdf
的行上执行任何过滤/异常值删除。之后,newdf
应该只包含您希望保留的行。
则只保留df
中索引在newdf
中的行。参考
df = df[df.index.isin(newdf.index)]
除了@ louning解决方案。对于分类变量,不能使用zscore,但可以将低值类视为异常值。你可以为计数设置一个阈值。
玩具数据集的示例:
import random
import pandas as pd
colors = []
for i in range(100):
colors.append(random.choices(['yellow','white', 'red'], weights = [10, 1, 2])[0])
df = pd.DataFrame(colors, columns=['colors'])
我随机生成一列,分别有黄色、白色和红色的分类值,权重分别为10,1,2。
使用value_count()
pandas方法可以计算列
df['colors'].value_counts()
>>> yellow 68
red 20
white 12
Name: colors, dtype: int64
现在您可以设置一个阈值,并删除稀疏填充的类别,如白色。
@Ipounng的解决方案在现成的复制粘贴代码:
def remove_outliers(df):
newdf = df.select_dtypes(include=np.number)
newdf = newdf[(np.abs(stats.zscore(newdf)) < 3).all(axis=1)]
df = df[df.index.isin(newdf.index)]
return df