KeyError를주는 len (string)을 포함하는 조건식을 기반으로 팬더 DataFrame에서 행을 삭제합니다.


303

팬더 DataFrame이 있고 특정 열의 문자열 길이가 2보다 큰 행을 삭제하고 싶습니다.

나는 이것을 할 수있을 것으로 기대한다 ( 이 답변에 따라 ) :

df[(len(df['column name']) < 2)]

그러나 나는 단지 오류를 얻는다 :

KeyError: u'no item named False'

내가 뭘 잘못하고 있죠?

(참고 : df.dropna()any가 포함 된 행을 제거 하는 데 사용할 수는 NaN있지만 조건식을 기반으로 행을 제거하는 방법을 보지 못했습니다.)

답변:


168

당신이 할 때 len(df['column name'])당신이 한 수, DataFrame의 행, 즉 수를 얻고있다 (즉, 열 자체의 길이). len열의 각 요소에 적용하려면 을 사용하십시오 df['column name'].map(len). 그래서 시도하십시오

df[df['column name'].map(len) < 2]

3
나는 목록 이해를 사용하는 방법을 생각해 df[[(len(x) < 2) for x in df['column name']]]냈지만, 당신은 훨씬 훌륭합니다. 당신의 도움을 주셔서 감사합니다!
sjs

13
누군가 더 복잡한 비교가 필요한 경우 람다를 항상 사용할 수 있습니다. df[df['column name'].map(lambda x: str(x)!=".")]
4lberto

1
어떤 이유로 @ 4lberto 게시 한 옵션을 제외하고 다른 옵션은 효과가 없었습니다. 나는에있어 pandas 0.23.43.6 파이썬
goelakash

1
.copy()나중에이 데이터 프레임을 편집하려는 경우 마지막 에 a 를 추가합니다 (예 : 새 열을 할당하면 "DataFrame의 슬라이스 사본에 값을 설정하려고합니다"경고가 발생 함)
PlasmaBinturong

806

이 질문의 원래 제목 "조건부 표현식을 기반으로 pandas DataFrame에서 행을 삭제하는 방법"에 직접 대답하려면 (OP의 문제는 아니지만 OP가 문제가되는 다른 사용자를 도울 수 있음을 이해합니다)이를 수행하는 한 가지 방법은 그만큼 드롭 방법 :

df = df.drop(some labels)

df = df.drop(df[<some boolean condition>].index)

'score'열이 <50 인 모든 행을 제거하려면 다음을 수행하십시오.

df = df.drop(df[df.score < 50].index)

인플레 이스 버전 (의견에서 지적)

df.drop(df[df.score < 50].index, inplace=True)

여러 조건

(보다 부울 인덱싱 )

연산자는 |for or, &for and~ for not입니다. 괄호를 사용하여 그룹화해야합니다.

'score'열이 <50 및> 20 인 모든 행을 제거하려면

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)


32
드롭 기능이 인플레 이스 교체를 지원한다는 점을 말하고 싶습니다. 즉. 해결책은 df.drop (df [df.score <50] .index, inplace = True)와 같습니다. 그럼에도 불구하고 "인덱스"트릭을 몰랐다. 나를 많이 도와주었습니다
Quickbeam2k1 2016 년

9
이 인덱스 트릭을 사용하기 전에 인덱스 값이 고유한지 (또는 call reset_index()) 확인해야합니다 . 많은 행으로가는 길이 데이터 프레임에서 떨어질 때 어려운 방법을 발견했습니다.
Jay

3
열 유형이 str 인 모든 행을 어떻게 삭제합니까? 목록 열 유형 만 유지하고 싶습니다. 나는 시도 test = df.drop(df[df['col1'].dtype == str].index)하지만 오류 얻을 KeyError: False 나는 또한 시도를 df.drop(df[df.col1.dtype == str].index)하고 df.drop(df[type(df.cleaned_norm_email) == str].index)있지만 아무것도 작동하는 것 같다 없다? 누구든지 조언 할 수 있습니다. 감사! @User
PyRsquared

1
이것은 오래된 질문이지만 ... @ aquatically-challenged-fish는 이것보다 훨씬 빠릅니다. df[(df.score < 50) & (df.score > 20)]답의 일부로 계산 하십시오. 이 작업을 반대로하면 df = df[(df.score >= 50) | (df.score <= 20)]훨씬 빠르게 답변을 얻을 수 있습니다.
Roobie Nuby

1
@RoobieNuby-그들은 같은 조건이 아닙니다.
Nguai al

106

DataFrame필터링 된 버전 자체를에 할당 할 수 있습니다 .

df = df[df.score > 50]

이것은 다음보다 빠릅니다 drop.

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test[test.x < 0]
# 54.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test.drop(test[test.x > 0].index, inplace=True)
# 201 ms ± 17.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test.drop(test[test.x > 0].index)
# 194 ms ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

또는 조건을 사용하여 여러 열을 어떻게 확인합니까?
Piyush S. Wanare


9

@User의 일반 솔루션을 확장하여 drop 무료 대안 것입니다. 이것은 질문의 제목을 기준으로 여기에 지시 된 사람들을위한 것입니다 (OP의 문제가 아님).

음수 값을 가진 모든 행을 삭제한다고 가정하십시오. 하나의 라이너 솔루션은 다음과 같습니다.

df = df[(df > 0).all(axis=1)]

단계별 설명 :-

5x5 랜덤 정규 분포 데이터 프레임을 생성합시다

np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,5), columns=list('ABCDE'))
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
1 -0.977278  0.950088 -0.151357 -0.103219  0.410599
2  0.144044  1.454274  0.761038  0.121675  0.443863
3  0.333674  1.494079 -0.205158  0.313068 -0.854096
4 -2.552990  0.653619  0.864436 -0.742165  2.269755

조건이 음수를 삭제하도록합니다. 조건을 만족하는 부울 df :-

df > 0
      A     B      C      D      E
0   True  True   True   True   True
1  False  True  False  False   True
2   True  True   True   True   True
3   True  True  False   True  False
4  False  True   True  False   True

조건을 만족하는 모든 행에 대한 부울 시리즈 행의 요소가 실패하면 해당 행이 false로 표시됩니다.

(df > 0).all(axis=1)
0     True
1    False
2     True
3    False
4    False
dtype: bool

마지막으로 조건에 따라 데이터 프레임에서 행을 필터링합니다.

df[(df > 0).all(axis=1)]
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
2  0.144044  1.454274  0.761038  0.121675  0.443863

위의 작업 과 필터 를 실제로 삭제 하기 위해 다시 df로 할당 할 수 있습니다
df = df[(df > 0).all(axis=1)]

NaN을 포함하는 행을 필터링하기 위해 쉽게 확장 할 수 있습니다 (숫자가 아닌 항목).
df = df[(~df.isnull()).all(axis=1)]

열 E가 음수 인 모든 행을 삭제하십시오.

df = df[(df.E>0)]

@User의 drop솔루션이 원시 열 기반 필터링보다 느린 이유에 대한 프로파일 링 통계로 끝내고 싶습니다 .

%timeit df_new = df[(df.E>0)]
345 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit dft.drop(dft[dft.E < 0].index, inplace=True)
890 µs ± 94.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

열은 기본적으로이다 SeriesNumPy그것은 어떤 비용없이 인덱싱 할 수 배열입니다. 기본 메모리 구성이 실행 속도에 미치는 영향에 관심이있는 사람들에게는 팬더 속도 향상에 대한 훌륭한 링크가 있습니다 .


6

팬더에서는 str.len경계를 사용하고 부울 결과를 사용하여 필터링 할 수 있습니다.

df[df['column name'].str.len().lt(2)]

3

열 값에 대한 복잡한 조건에 따라 데이터 프레임의 행을 삭제하려면 위에 표시된 방식으로 작성하는 것이 복잡 할 수 있습니다. 항상 작동하는 다음과 같은 간단한 솔루션이 있습니다. 'header'로 열을 삭제한다고 가정하고 해당 열을 목록에서 먼저 가져옵니다.

text_data = df['name'].tolist()

이제 목록의 모든 요소에 일부 기능을 적용하고 팬더 시리즈에 넣으십시오.

text_length = pd.Series([func(t) for t in text_data])

내 경우에는 방금 토큰 수를 얻으려고했습니다.

text_length = pd.Series([len(t.split()) for t in text_data])

이제 데이터 프레임에 위 시리즈의 열을 하나 더 추가하십시오.

df = df.assign(text_length = text_length .values)

이제 다음과 같은 새 열에 조건을 적용 할 수 있습니다.

df = df[df.text_length  >  10]
def pass_filter(df, label, length, pass_type):

    text_data = df[label].tolist()

    text_length = pd.Series([len(t.split()) for t in text_data])

    df = df.assign(text_length = text_length .values)

    if pass_type == 'high':
        df = df[df.text_length  >  length]

    if pass_type == 'low':
        df = df[df.text_length  <  length]

    df = df.drop(columns=['text_length'])

    return df
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.