【问题标题】:Pandas: Subset data frame using list, keeping duplicates multiple timesPandas:使用列表的子集数据框,多次保持重复
【发布时间】:2019-07-29 04:06:21
【问题描述】:

我有一个包含重复值的大列表,我希望使用列表值对数据框进行子集化。通常我会使用.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']

所以我想在每次出现时返回一个包含所有行的数据框。每次列表中出现一个项目时,我都想返回相应的行。

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

编辑:所以 Chris 的建议有效,并提供了预期的输出:

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

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

【问题讨论】:

  • pd.concat([df[df['c'].eq(x)] for x in lst]) - 你是这个意思吗?
  • 预期输出是什么?

标签: python pandas dataframe duplicates subset


【解决方案1】:

IIUC,将pandas.concat 与列表理解一起使用:

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

另一种方法是在列表中使用value_counts 方法创建一个助手Series,并使用.isin 方法减少原始DataFrame 大小过滤:

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]

【讨论】:

  • 嗨,克里斯。这有效(我将其添加到问题中以提供预期的输出)但比 .isin 方法慢得多。
  • @spiral01 我添加了一个替代解决方案。很想知道它是否表现更好
  • 嗨,克里斯。谢谢。两种解决方案都有效,而您的第二个解决方案更快。最快的解决方案是@jezrael,尽管它仍然比 .isin 慢得多(在 600kx6 的数据帧上,使用 jezrael 的方法使用 20k 项的列表大约需要 4 分钟,而 .isin 只需要几秒钟)。
【解决方案2】:

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

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)

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-06-01
      • 1970-01-01
      • 2019-09-06
      • 1970-01-01
      • 2023-03-10
      • 2021-12-27
      • 1970-01-01
      • 2018-11-02
      • 2017-01-22
      相关资源
      最近更新 更多