熊猫:使用列表对数据框进行分组,多次保留重复项

时间:2019-03-07 10:01:52

标签: python pandas dataframe duplicates subset

我有一个很大的列表,其中包含重复的值,我希望使用列表值对数据帧进行子集化。通常,我会使用.isin方法,但是我想保留重复的行。这是一些示例代码:

df = pd.DataFrame(np.array([[1, 2, 'car'], [4, 5, 'bike'], [1, 2, 'train'], [1, 2, 'car'], [1, 2, 'train']]),columns=['a', 'b', 'c'])

lst = ['car', 'bike', 'car', 'car']

因此,我想返回一个包含所有行的数据帧。每当列表中出现一项时,我都想返回相应的行。

在诸如上述的简单数据集上,我可以遍历列表并将返回的值附加到新数据框中,但是在大型数据集上,这似乎要花费很长时间。有什么建议吗?

编辑:因此克里斯的建议起作用了,并使用以下方法提供了预期的输出:

pd.concat([df[df['c'].eq(x)] for x in lst])

但是,与使用循环相比,使用.isin方法处理大型数据时,这非常慢。添加了此编辑,以便可以创建预期的输出。

3 个答案:

答案 0 :(得分:1)

IIUC,结合列表理解使用pandas.concat

df_new = pd.concat([df[df['c'].eq(x)] for x in lst], ignore_index=True)

另一种方法可能是在列表上使用Series方法创建一个辅助value_counts并使用DataFrame方法减少原始.isin大小的过滤:

s = pd.Series(lst).value_counts()
df = df[df['c'].isin(set(lst))]

idx = np.concatenate([df[df['c'].eq(i)].index.repeat(r) for i, r in s.iteritems()])

df_new = df.loc[idx]

答案 1 :(得分:1)

第一步是仅过滤匹配的值:

df = df[df['c'].isin(lst)]

然后将索引变平以匹配条件,然后使用loc进行重复,np.repeat也可以,但是它将所有列都转换为字符串,因此不能在这里使用:

idx = [y for x in lst for y in df.index[df['c'].values == x]]
df_new = df.loc[idx].reset_index(drop=True)
print (df_new)
   a  b     c
0  1  2   car
1  1  2   car
2  4  5  bike
3  1  2   car
4  1  2   car
5  1  2   car
6  1  2   car

如果可能有许多重复值,则仅过滤一次,然后重复索引值:

ser = pd.Series(lst)
idx = ser.map({k:df.index[df['c'].values == k] for k, v in ser.value_counts().items()})
df_new = df.loc[list(chain.from_iterable(idx))].reset_index(drop=True)
print (df_new)
   a  b     c
0  1  2   car
1  1  2   car
2  4  5  bike
3  1  2   car
4  1  2   car
5  1  2   car
6  1  2   car

另一种解决方案:

from  itertools import chain
from collections import Counter

d = {k:df.index[df['c'].values == k] for k, v in Counter(lst).items()}
idx = [y for x in lst for y in d[x]]
df_new = df.loc[idx].reset_index(drop=True)

答案 2 :(得分:0)

如果我正确理解了您的问题,groupby可以帮助您

gr = df.groupby('c')
for i in lst:
    subset = gr.get_group(i)
    # process subset...