【问题标题】:Better way to iterate through rows in a data frame and conditionally assign a group遍历数据框中的行并有条件地分配组的更好方法
【发布时间】:2022-09-24 01:49:11
【问题描述】:

我创建了一个函数,用于分配每行所属的纬度和经度类别。但是,这个问题太慢了。我怎样才能提高性能?

这是我的代码。

def assign_segment(use_df: pd.DataFrame, 
                   lat_categories: pd.core.indexes.interval.IntervalIndex, 
                   lng_categories: pd.core.indexes.interval.IntervalIndex) -> pd.DataFrame:
    \"\"\"
    Assign segments based on the latitude and longtitude column of \"use_tb\".

    Parameters
    ----------
    use_df : pd.DataFrame
        Use DataFrame.
    lat_categories : pd.core.indexes.interval.IntervalIndex
        Latitude interval categories.
        (ex.) IntervalIndex([(35.809, 35.816], (35.816, 35.824], 
                             (35.824, 35.832], (35.832, 35.84], (35.84, 35.848]])
    lng_categories : pd.core.indexes.interval.IntervalIndex
        Lontitude interval categories.
        (ex.) IntervalIndex([(128.668, 128.685], (128.685, 128.703], 
                             (128.703, 128.72], (128.72, 128.737]])

    Returns
    -------
    use_df : pd.DataFrame
        \"use_df\" with segments assigned.
    \"\"\"
    segment = []

    # iterate each row and get the segment according to latitude and longitude
    for idx, row in use_df.iterrows():
        use_lat = row[\'use_lat\']
        use_lng = row[\'use_lng\']

        for lat_idx, lat_category in enumerate(lat_categories):
            if use_lat in lat_category:
                lat_segment = lat_idx + 1
                break
        for lng_idx, lng_category in enumerate(lng_categories):
            if use_lng in lng_category:
                lng_segment = lng_idx + 1
                break

        num_lng_grid = len(lat_categories)      # number of longtitude grid
        lng_num_digits = len(str(num_lng_grid)) # number of digits of lng_grid
        segment.append((lat_segment*10**lng_num_digits)+lng_segment)
        
    # create the segment column with the segment list that we created in this function
    use_df[\'segment\'] = segment

    return use_df

标签: pandas dataframe for-loop iteration


【解决方案1】:

iterrows() 在遍历行时非常慢。一些开发人员认为永远不应该使用 iterrows。我们必须求助于一些向量化来加速代码。你可以使用tqdm

from tqdm import tqdm
def assign_segment(use_df: pd.DataFrame, 
                   lat_categories: pd.core.indexes.interval.IntervalIndex, 
                   lng_categories: pd.core.indexes.interval.IntervalIndex) -> pd.DataFrame:
    """
    Assign segments based on the latitude and longtitude column of "use_tb".

    Parameters
    ----------
    use_df : pd.DataFrame
        Use DataFrame.
    lat_categories : pd.core.indexes.interval.IntervalIndex
        Latitude interval categories.
        (ex.) IntervalIndex([(35.809, 35.816], (35.816, 35.824], 
                             (35.824, 35.832], (35.832, 35.84], (35.84, 35.848]])
    lng_categories : pd.core.indexes.interval.IntervalIndex
        Lontitude interval categories.
        (ex.) IntervalIndex([(128.668, 128.685], (128.685, 128.703], 
                             (128.703, 128.72], (128.72, 128.737]])

    Returns
    -------
    use_df : pd.DataFrame
        "use_df" with segments assigned.
    """
    segment = []

    # iterate each row and get the segment according to latitude and longitude
    for row in tqdm(use_df.to_dict('records')):
        use_lat = row['use_lat']
        use_lng = row['use_lng']

        for lat_idx, lat_category in enumerate(lat_categories):
            if use_lat in lat_category:
                lat_segment = lat_idx + 1
                break
        for lng_idx, lng_category in enumerate(lng_categories):
            if use_lng in lng_category:
                lng_segment = lng_idx + 1
                break

        num_lng_grid = len(lat_categories)      # number of longtitude grid
        lng_num_digits = len(str(num_lng_grid)) # number of digits of lng_grid
        segment.append((lat_segment*10**lng_num_digits)+lng_segment)
        
    # create the segment column with the segment list that we created in this function
    use_df['segment'] = segment

    return use_df

值得阅读这些文章:

How To Make Your Pandas Loop 71803 Times Faster

Stop Using iterrows()

【讨论】:

  • 我得到 TypeError: 'module' object is not callable
  • 对不起。你应该像这样导入模块:from tqdm import tqdm
  • 好的!我正在尝试 - 我还阅读了您添加的两个参考资料。那么,tqdm 使用矢量化?不知道谢谢你的信息!
【解决方案2】:

这就是你在这里需要做的一切......

lat_segments = lat_categories.get_indexer(df['use_lat'])
lng_segments = lng_categories.get_indexer(df['use_lng'])

num_lng_grid = len(lat_categories)
lng_num_digits = len(str(num_lng_grid))

df['segment'] = (lat_segments*10**lng_num_digits)+lng_segments

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    相关资源
    最近更新 更多