【问题标题】:Is there a faster alternative to getting a subset of a DataFrame?是否有更快的替代方法来获取 DataFrame 的子集?
【发布时间】:2018-09-26 05:49:00
【问题描述】:

我目前正在处理一些 Python 代码,我正在尝试检索列值等于某个值的 DataFrame 的子集。我是这样做的:

for i in brands.index:
    current_brand = brands.get_value(i, 'Car Brand')
    my_dataframe_subset = my_dataframe[my_dataframe['Brand'] == current_brand]  

这当然适用于制作子集,但我在循环中不断地这样做,数千次。我发现这是我执行速度的一个巨大瓶颈,但不幸的是'current_brand'会改变循环的每次迭代,所以我看不到另一种方式。是否有更快的替代方法来获得不会导致如此巨大延迟的这个子集?

谢谢

编辑: 这是我的代码在做什么的一个更现实的例子。显然数据是乱码,但我希望你明白:

------------------------
|Person | Car Brand |
|------------------------
|'dave' | 'Toyota'  |
|'mike' | 'Ford'    |
|'sally'| 'Ford'    |
|'doug' | 'BMW'     |
------------------------
my_list = []
for i in brands.index:
    current_person = brands.get_value(i, 'Person')
    current_brand = brands.get_value(i, 'Car Brand')
    my_dataframe_subset = my_dataframe[my_dataframe['Brand'] == current_brand] 

    for i_b in my_dataframe_subset.index:
        #do stuff with current_person and current_brand
        car_colour = my_dataframe_subset(i_b, 'Colour')
        car_speed = my_dataframe_subset(i_b, 'Speeds')
        my_dict = {'person': current_person, 'brand': current_brand, 'colour': car_colour, 'speed': car_speed}
        my_list.append(my_dict)

【问题讨论】:

  • 可以添加一些数据样本吗?
  • 具体来说,brands 数据框包含的唯一值是否少于my_dataframe 中的唯一值?
  • @jezrael 完成,添加
  • @PL200 - 你能解释更多#do stuff with current_person and current_brand吗?
  • @jezrael 当然,我已经附加了 OP。这些数据没有多大意义,但你可以希望看到我想要实现的目标。

标签: python pandas loops dataframe


【解决方案1】:

我认为需要merge 与默认内连接:

brands = pd.DataFrame({
        'Person': ['dave', 'mike', 'sall', 'doug'], 
        'Car Brand': ['Kia', 'Ford', 'Ford', 'BMW']
})

my_dataframe = pd.DataFrame({
        'Brand':['Toyota','Toyota','BMW', 'BMW', 'BMW', 'Ford'],
         'Speeds':[40,50,20,10,30,40],
         'Colour':list('abcdef')
})
print (my_dataframe)
    Brand  Speeds Colour
0  Toyota      40      a
1  Toyota      50      b
2     BMW      20      c
3     BMW      10      d
4     BMW      30      e
5    Ford      40      f

d = {'Car Brand':'Brand'}
df = brands.rename(columns=d).merge(my_dataframe, on='Brand')
print (df)
  Person Brand  Speeds Colour
0   mike  Ford      40      f
1   sall  Ford      40      f
2   doug   BMW      20      c
3   doug   BMW      10      d
4   doug   BMW      30      e

如果需要字典列表:

my_list = df.to_dict(orient='records')

【讨论】:

  • @PL200 - 你能添加一些数据样本吗?因为不确定是否理解。
  • 嗨@jezarel,向 OP 添加了更好的代码示例,以说明为什么我不确定此解决方案是否有效。
  • @PL200 - 返回print (my_dataframe.columns.tolist())print (brands.columns.tolist()) ?
  • 没关系,这是我自己的错误。该解决方案完美运行。将我的执行时间从约 10 分钟缩短到约 5 秒。谢谢!
  • @PL200 - 超级 ;)
【解决方案2】:

1) 遍历 brands 数据框中的所有独特品牌。

2) 过滤my_dataframe 数据框中与品牌匹配的行。

根据您希望如何处理空集(即,当my_dataframe 中没有与来自brands 的匹配的brand 时),您可以简单地按Brand 中的Brand 分组,如图所示@jezrael 和 @chthonicdaemon。

for current_brand in brands['Car Brand'].unique():
    brand_df = my_dataframe[my_dataframe['Brand'] == current_brand]
    # Do stuff with filtered brand dataframe.

【讨论】:

    【解决方案3】:

    让我们从一些示例数据开始:

    import pandas
    brands = pandas.DataFrame({'Car Brand': ['Toyota', 'Honda']})
    my_dataframe = pandas.DataFrame({'Brand': ['Toyota']*4 + ['Honda']*4, 'Value': [1]*8})
    

    对于此数据中的情况,brands 数据框仅包含 my_dataframe.Brand 列中的唯一值。这种情况下可以直接使用groupby

    for current_brand, my_dataframe_subset in my_dataframe.groupby('Brand'):
        # do stuff with subset
    

    如果brands中的品牌比my_dataframe中的少,可以过滤掉:

    dataset_for_brands = my_dataframe[my_dataframe.Brand.isin(brands['Car Brand'])]
    for current_brand, my_dataframe_subset in dataset_for_brands.groupby('Brand'):
        # do stuff with subset
    

    如果您正在计算组的聚合,您甚至可以完全避免循环,所以假设您想要每个组的平均值,您可以这样做

    my_dataframe.groupby('Brand').Value.mean()
    

    直接得到答案:

    Brand
    Honda     1
    Toyota    1
    

    【讨论】:

    • @jezrael 你能说得更具体点吗?
    • 因为好像有2DataFrames。
    • 我的帖子是在 OP 添加第二个数据框之前发布的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-18
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多