我有一个很大的列表,其中包含重复的值,我希望使用列表值对数据帧进行子集化。通常,我会使用.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
方法处理大型数据时,这非常慢。添加了此编辑,以便可以创建预期的输出。
答案 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...