删除包含混合dtype的df中的异常值



我正在研究包含数值列以及字符串列(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