[python] 판다 데이터 프레임의 새 열에 목록에서 찾은 ID 추가

다음 데이터 프레임 (정수 열과 정수 목록이있는 열)이 있다고 가정 해보십시오.

      ID                   Found_IDs
0  12345        [15443, 15533, 3433]
1  15533  [2234, 16608, 12002, 7654]
2   6789      [43322, 876544, 36789]

또한 별도의 ID 목록 …

bad_ids = [15533, 876544, 36789, 11111]

그것을 감안할 때 df['ID']열과 색인을 무시 하고 bad_ids목록 의 ID 가 df['Found_IDs']열에 언급되어 있는지 확인하고 싶습니다 . 지금까지 가지고있는 코드는 다음과 같습니다

df['bad_id'] = [c in l for c, l in zip(bad_ids, df['Found_IDs'])]

이것은 작동하지만 bad_ids목록이 데이터 프레임보다 길고 실제 데이터 세트의 경우 bad_ids목록이 데이터 프레임보다 훨씬 짧을 경우에만 작동합니다 . bad_ids목록을 두 요소로만 설정하면 …

bad_ids = [15533, 876544]

매우 인기있는 오류가 발생합니다 (같은 오류로 많은 질문을 읽었습니다) …

ValueError: Length of values does not match length of index

목록을 시리즈로 변환하려고 시도했습니다 (오류가 변경되지 않음). 또한 False이해 줄을 수행 하기 전에 새 열을 추가하고 모든 값을 설정하려고 시도했습니다 (오류가 변경되지 않음).

두 가지 질문 :

  1. 데이터 프레임보다 짧은 목록에 대해 코드 (아래)를 작동 시키려면 어떻게해야합니까?
  2. 실제 ID를 다시 df['bad_id']열에 기록하는 코드를 얻으려면 어떻게해야합니까 (True / False보다 유용)?

에 대한 예상 출력 bad_ids = [15533, 876544]:

      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    True
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    True

bad_ids = [15533, 876544](ID (들)에 대한 이상적인 출력 은 새로운 열에 기록됩니다) :

      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    15533
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    876544

암호:

import pandas as pd

result_list = [[12345,[15443,15533,3433]],
        [15533,[2234,16608,12002,7654]],
        [6789,[43322,876544,36789]]]

df = pd.DataFrame(result_list,columns=['ID','Found_IDs'])

# works if list has four elements
# bad_ids = [15533, 876544, 36789, 11111]

# fails if list has two elements (less elements than the dataframe)
# ValueError: Length of values does not match length of index
bad_ids = [15533, 876544]

# coverting to Series doesn't change things
# bad_ids = pd.Series(bad_ids)
# print(type(bad_ids))

# setting up a new column of false values doesn't change things
# df['bad_id'] = False

print(df)

df['bad_id'] = [c in l for c, l in zip(bad_ids, df['Found_IDs'])]

print(bad_ids)

print(df)



답변

np.intersect1d두 목록의 교차를 얻기 위해 사용 :

df['bad_id'] = df['Found_IDs'].apply(lambda x: np.intersect1d(x, bad_ids))

      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]

또는 sets다음의 교차를 사용하는 바닐라 파이썬으로 :

bad_ids_set = set(bad_ids)
df['Found_IDs'].apply(lambda x: list(set(x) & bad_ids_set))


답변

모든 사용 값으로 Found_IDs열의 목록 값을 모두 테스트 bad_ids하려면 다음을 수행하십시오.

bad_ids = [15533, 876544]

df['bad_id'] = [any(c in l for c in bad_ids) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    True
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    True

모든 경기를 원한다면 :

df['bad_id'] = [[c for c in bad_ids if c in l] for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]

첫 번째 일치의 경우 빈 목록이 설정된 False경우 가능한 해결책이지만 부울과 숫자를 혼합하지 않는 것이 좋습니다.

df['bad_id'] = [next(iter([c for c in bad_ids if c in l]), False) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]   15533
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]  876544

세트 솔루션 :

df['bad_id'] = df['Found_IDs'].map(set(bad_ids).intersection)
print (df)

      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   {15533}
1  15533  [2234, 16608, 12002, 7654]        {}
2   6789      [43322, 876544, 36789]  {876544}

또한 목록 이해와 비슷합니다.

df['bad_id'] = [list(set(bad_ids).intersection(l)) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]


답변

np.any를 적용하고 사용할 수 있습니다.

df['bad_id'] = df['Found_IDs'].apply(lambda x: np.any([c in x for c in bad_ids]))

이 bad_id를 검색하려면 Found_ID에 bad_id가 있으면 bool을 반환합니다.

df['bad_id'] = df['Found_IDs'].apply(lambda x: [*filter(lambda x: c in x, bad_ids)])

found_ids에서 bad_id 목록을 리턴합니다. 0이 있으면 []를 리턴합니다.


답변

사용 merge하고 concat모든 경기를 반환하는 색인에 의해 그룹화 동안.

bad_ids = [15533, 876544, 36789, 11111]

df2 = pd.concat(
    [
        df,
        pd.merge(
            df["Found_IDs"].explode().reset_index(),
            pd.Series(bad_ids, name="bad_ids"),
            left_on="Found_IDs",
            right_on="bad_ids",
            how="inner",
        )
        .groupby("index")
        .agg(bad_ids=("bad_ids", list)),
    ],
    axis=1,
).fillna(False)
print(df2)


      ID                   Found_IDs          bad_ids
0  12345        [15443, 15533, 3433]          [15533]
1  15533  [2234, 16608, 12002, 7654]            False
2   6789      [43322, 876544, 36789]  [876544, 36789]


답변

분해 및 그룹 별 집계 사용

s = df['Found_IDs'].explode()
df['bad_ids'] = s.isin(bad_ids).groupby(s.index).any()

에 대한 bad_ids = [15533, 876544]

>>> df
      ID                   Found_IDs  bad_ids
0  12345        [15443, 15533, 3433]     True
1  15533  [2234, 16608, 12002, 7654]    False
2   6789      [43322, 876544, 36789]     True

또는

일치하는 값을 얻으려면

s = df['Found_IDs'].explode()
s.where(s.isin(bad_ids)).groupby(s.index).agg(lambda x: list(x.dropna()))

에 대한 bad_ids = [15533, 876544]

      ID                   Found_IDs   bad_ids
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]


답변