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

Removing outliers in a df containing mixed dtype

我正在处理一个包含数字列和字符串列的 pandas DataFrame(dtype 是 object),我想删除包含异常值的行柱子。换句话说,检测每列中的异常值并删除相应的行。

我找到了两个解决方案,但都没有考虑到我的 df 不只包含数字,因此它们都会导致错误(我假设遇到字符串时)。

Way 1:

from scipy import stats
df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]

returnsTypeError: unsupported operand type(s) for /: 'str' and 'int'。 这就是为什么我猜错误是由 df 混合数据类型引起的。

Way 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)

returns 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'

你会如何解决这个问题?

编辑:想法是跳过非数字列,忽略它们。

我会将问题分成几个阶段:

首先,确定要执行离群值删除的(数字)列。 Reference

newdf = df.select_dtypes(include=np.number)

现在对 newdf 的行执行任何 filtering/outlier 删除操作。之后,newdf 应该只包含您希望保留的行。

然后只保留 df 那些索引在 newdf 中的行。

df = df[df.index.isin(newdf.index)]

@Ipounng 在copy-paste 中的解决方案现成代码:

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

除了@lpounng 解决方案。对于分类变量,您不能使用 zscore,但您可以将低值 class 视为异常值。您可以为值计数设置阈值。

玩具数据集示例:

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

现在您可以设置一个阈值并删除人口稀少的类别,例如美国白人。