답변:
데이터 프레임에 여러 열이 있고 하나 이상의 열에 특이 치가있는 모든 행을 제거하려면 다음식이 한 번에 수행됩니다.
df = pd.DataFrame(np.random.randn(100, 3))
from scipy import stats
df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
기술:
boolean
인덱싱 사용numpy.array
df = pd.DataFrame({'Data':np.random.normal(size=200)})
# example dataset of normally distributed data.
df[np.abs(df.Data-df.Data.mean()) <= (3*df.Data.std())]
# keep only the ones that are within +3 to -3 standard deviations in the column 'Data'.
df[~(np.abs(df.Data-df.Data.mean()) > (3*df.Data.std()))]
# or if you prefer the other way around
시리즈의 경우 비슷합니다.
S = pd.Series(np.random.normal(size=200))
S[~((S-S.mean()).abs() > 3*S.std())]
DataFrame.abs()
FYI이기도합니다.DataFrame.clip()
clip()
Jeff 의 경우 윤곽선이 제거되지 않습니다. 윤곽선 df.SOME_DATA.clip(-3std,+3std)
을 + 3std 또는 -3std에 할당
df_new = df[np.abs(df - df.mean()) <= (3 * df.std())]
. 그러나 Series 또는 단일 열에 적용하는 것과 달리 이는 특이 치를 대체 np.nan
하여 DataFrame의 모양을 유지하므로 누락 된 값을 채우기 위해 보간이 필요할 수 있습니다.
각 데이터 프레임 열에 대해 다음을 통해 Quantile을 얻을 수 있습니다.
q = df["col"].quantile(0.99)
다음으로 필터링하십시오.
df[df["col"] < q]
하한값과 상한값을 제거해야하는 경우 조건을 AND 문과 결합하십시오.
q_low = df["col"].quantile(0.01)
q_hi = df["col"].quantile(0.99)
df_filtered = df[(df["col"] < q_hi) & (df["col"] > q_low)]
이 답변은 @tanemaki가 제공하는 답변과 비슷하지만 lambda
대신 표현식을 사용합니다 scipy stats
.
df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))
df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]
하나의 열 (예 : 'B') 만 세 표준 편차 내에있는 DataFrame을 필터링하려면 다음을 수행하십시오.
df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
롤링 기준으로이 z- 점수를 적용하는 방법은 여기를 참조하십시오. 팬더 데이터 프레임에 적용된 롤링 Z- 점수
#------------------------------------------------------------------------------
# accept a dataframe, remove outliers, return cleaned data in a new dataframe
# see http://www.itl.nist.gov/div898/handbook/prc/section1/prc16.htm
#------------------------------------------------------------------------------
def remove_outlier(df_in, col_name):
q1 = df_in[col_name].quantile(0.25)
q3 = df_in[col_name].quantile(0.75)
iqr = q3-q1 #Interquartile range
fence_low = q1-1.5*iqr
fence_high = q3+1.5*iqr
df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
return df_out
숫자 및 비 숫자 속성 을 다루는 답변을 보지 못 했으므로 여기에 보완 답변이 있습니다.
수치 속성에서만 특이 치를 삭제하려고 할 수 있습니다 (범주 변수는 특이 치일 수 없음).
기능 정의
숫자가 아닌 속성이 존재할 때 데이터를 처리하기 위해 @tanemaki의 제안을 확장했습니다.
from scipy import stats
def drop_numerical_outliers(df, z_thresh=3):
# Constrains will contain `True` or `False` depending on if it is a value below the threshold.
constrains = df.select_dtypes(include=[np.number]) \
.apply(lambda x: np.abs(stats.zscore(x)) < z_thresh, reduce=False) \
.all(axis=1)
# Drop (inplace) values set to be rejected
df.drop(df.index[~constrains], inplace=True)
용법
drop_numerical_outliers(df)
예
df
골목, 토지 등고선, 판매 가격 등 주택에 대한 일부 가치가 있는 데이터 세트 를 상상해보십시오 . 예 : 데이터 문서
먼저, 산점도 (z-score Thresh = 3)로 데이터를 시각화하려고합니다.
# Plot data before dropping those greater than z-score 3.
# The scatterAreaVsPrice function's definition has been removed for readability's sake.
scatterAreaVsPrice(df)
# Drop the outliers on every attributes
drop_numerical_outliers(train_df)
# Plot the result. All outliers were dropped. Note that the red points are not
# the same outliers from the first plot, but the new computed outliers based on the new data-frame.
scatterAreaVsPrice(train_df)
reduce=False
부터 pandas
result_type='reduce'
합니다 reduce=False
.
데이터 프레임의 각 계열에 대해 이상 치를 사용 between
하고 quantile
제거 할 수 있습니다 .
x = pd.Series(np.random.normal(size=200)) # with outliers
x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers
scipy.stats
방법을 보유 trim1()
하고 trimboth()
순위 제거 값의 도입 비율에 따라, 하나의 행에 아웃 라이어를 잘라.
trimboth
나를 위해 가장 쉬웠다.
다른 옵션은 특이 치의 영향을 완화하도록 데이터를 변환하는 것입니다. 데이터를 winsorizing하여이 작업을 수행 할 수 있습니다.
import pandas as pd
from scipy.stats import mstats
%matplotlib inline
test_data = pd.Series(range(30))
test_data.plot()
# Truncate values to the 5th and 95th percentiles
transformed_test_data = pd.Series(mstats.winsorize(test_data, limits=[0.05, 0.05]))
transformed_test_data.plot()
부울 마스크를 사용할 수 있습니다.
import pandas as pd
def remove_outliers(df, q=0.05):
upper = df.quantile(1-q)
lower = df.quantile(q)
mask = (df < upper) & (df > lower)
return mask
t = pd.DataFrame({'train': [1,1,2,3,4,5,6,7,8,9,9],
'y': [1,0,0,1,1,0,0,1,1,1,0]})
mask = remove_outliers(t['train'], 0.1)
print(t[mask])
산출:
train y
2 2 0
3 3 1
4 4 1
5 5 0
6 6 0
7 7 1
8 8 1
데이터 과학 여행의 초기 단계에 있으므로 아래 코드로 특이 치를 처리하고 있습니다.
#Outlier Treatment
def outlier_detect(df):
for i in df.describe().columns:
Q1=df.describe().at['25%',i]
Q3=df.describe().at['75%',i]
IQR=Q3 - Q1
LTV=Q1 - 1.5 * IQR
UTV=Q3 + 1.5 * IQR
x=np.array(df[i])
p=[]
for j in x:
if j < LTV or j>UTV:
p.append(df[i].median())
else:
p.append(j)
df[i]=p
return df
특이 치의 한계로 98 및 2 백분위 수를 구하십시오.
upper_limit = np.percentile(X_train.logerror.values, 98)
lower_limit = np.percentile(X_train.logerror.values, 2) # Filter the outliers from the dataframe
data[‘target’].loc[X_train[‘target’]>upper_limit] = upper_limit data[‘target’].loc[X_train[‘target’]<lower_limit] = lower_limit
데이터와 두 그룹으로 구성된 전체 예는 다음과 같습니다.
수입품 :
from StringIO import StringIO
import pandas as pd
#pandas config
pd.set_option('display.max_rows', 20)
두 그룹이있는 데이터 예 : G1 : 그룹 1 G2 : 그룹 2 :
TESTDATA = StringIO("""G1;G2;Value
1;A;1.6
1;A;5.1
1;A;7.1
1;A;8.1
1;B;21.1
1;B;22.1
1;B;24.1
1;B;30.6
2;A;40.6
2;A;51.1
2;A;52.1
2;A;60.6
2;B;80.1
2;B;70.6
2;B;90.6
2;B;85.1
""")
팬더 데이터 프레임으로 텍스트 데이터를 읽습니다.
df = pd.read_csv(TESTDATA, sep=";")
표준 편차를 사용하여 특이 치 정의
stds = 1.0
outliers = df[['G1', 'G2', 'Value']].groupby(['G1','G2']).transform(
lambda group: (group - group.mean()).abs().div(group.std())) > stds
필터링 된 데이터 값과 특이 값을 정의하십시오.
dfv = df[outliers.Value == False]
dfo = df[outliers.Value == True]
결과를 인쇄하십시오.
print '\n'*5, 'All values with decimal 1 are non-outliers. In the other hand, all values with 6 in the decimal are.'
print '\nDef DATA:\n%s\n\nFiltred Values with %s stds:\n%s\n\nOutliers:\n%s' %(df, stds, dfv, dfo)
특이 치를 제거하는 내 기능
def drop_outliers(df, field_name):
distance = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)
이상 치를 삭제하고 삭제하는 것이 통계적으로 잘못되었다고 생각합니다. 데이터를 원본 데이터와 다르게 만듭니다. 또한 데이터의 모양이 불균일하게되므로 가장 좋은 방법은 데이터를 로그 변환하여 특이 치의 영향을 줄이거 나 피하는 것입니다. 이것은 나를 위해 일했다 :
np.log(data.iloc[:, :])