web-dev-qa-db-ja.com

リストで見つかったIDをpandas dataframeの新しい列に追加します

次のデータフレームがあるとしましょう(整数の列と整数のリストの列)...

      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リストを2つの要素のみに設定すると...

bad_ids = [15533, 876544]

私は非常に人気のあるエラーを受け取ります(同じエラーで多くの質問を読みました)...

ValueError: Length of values does not match length of index

リストをシリーズに変換してみました(エラーは変わりません)。理解の行を実行する前に、新しい列を追加してすべての値をFalseに設定することも試みました(ここでもエラーの変更はありません)。

2つの質問:

  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)
11
MDR

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が存在する場合、これはブール値を返します。

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

これはfound_idsにあるbad_idsのリストを返します。0がある場合は[]を返します

1
Bruno Mello

mergeconcatを使用してインデックスをグループ化し、すべての一致を返します。

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]
1
Manakin

分解およびグループ化集約を使用する

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]
0
Vishnudev