【问题标题】:Generate a pandas dataframe with for-loop使用 for 循环生成 pandas 数据框
【发布时间】:2021-02-23 00:34:27
【问题描述】:

我生成了一个数据框(称为“行业”),用于存储来自我的经纪账户的信息(行业/行业、子行业、公司名称、当前价值、成本基础等)。

我想避免为每个扇区或子扇区硬编码过滤器来查找特定数据。我已经使用以下代码实现了这一点(我知道,不是很 Python,但我是编码新手):

for x in set(sectors_df['Sector']):
    x_filt = sectors_df['Sector'] == x
    #value in sect takes the sum of all current values in a given sector
    value_in_sect = round(sectors_df.loc[x_filt]['Current Value'].sum(), 2)
    #pct in sect is the % of the sector in the over all portfolio (total equals the total value of all sectors) 
    pct_in_sect = round((value_in_sect/total)*100 , 2)
    print(x, value_in_sect, pct_in_sect)

for sub in set(sectors_df['Sub Sector']):
    sub_filt = sectors_df['Sub Sector'] == sub
    value_of_subs = round(sectors_df.loc[sub_filt]['Current Value'].sum(), 2)
    pct_of_subs = round((value_of_subs/total)*100, 2)
    print(sub, value_of_subs, pct_of_subs)

我的打印报表产生了我想要的大部分信息,尽管我仍在研究如何为自己部门内的子部门的百分比编程。无论如何,我现在想将这些信息(value_in_sect、pct_in_sect 等)放入他们自己的数据帧中。最好的方法或最聪明的方法或最pythonic的方法是什么?我在想一本字典,然后从字典中创建一个数据框,但不确定。

【问题讨论】:

  • pandas.pivot_table 是你的朋友。您可以按部门和子部门分组获得百分比和总数。

标签: python pandas dataframe for-loop filter


【解决方案1】:

pandas 中的split-apply-combine process,特别是aggregation,是解决此问题的最佳方式。首先我会解释这个过程是如何手动工作的,然后我会展示 pandas 是如何在一行中完成的。

手动拆分-应用-合并

拆分

首先,将DataFrame分成同一个Sector的组。这涉及获取扇区列表并确定哪些行属于它(就像代码的前两行一样)。此代码贯穿 DataFrame 并构建一个字典,其中键为 Sectors 和对应于它的 sectors_df 的行索引列表。

sectors_index = {}
for ix, row in sectors_df.iterrows():
    if row['Sector'] not in sectors_index:
        sectors_index[row['Sector']] = [ix]
    else:
        sectors_index[row['Sector']].append(ix)

申请

在每个组上运行相同的函数,在本例中对 Current Value 求和并计算其百分比份额。也就是说,对于每个扇区,从 DataFrame 中获取相应的行并在代码的下一行中运行计算。我会将结果存储为字典字典:{'Sector1': {'value_in_sect': 1234.56, 'pct_in_sect': 11.11}, 'Sector2': ... },原因稍后会很明显:​​

sector_total_value = {}
total_value = sectors_df['Current Value'].sum()
for sector, row_indices in sectors_index.items():
    sector_df = sectors_df.loc[row_indices]
    current_value = sector_df['Current Value'].sum()
    sector_total_value[sector] = {'value_in_sect': round(current_value, 2),
                                  'pct_in_sect': round(current_value/total_value * 100, 2)
                                 }

(有关四舍五入的说明见脚注 1)

合并

最后,将函数结果收集到一个新的DataFrame中,其中索引为Sector。 pandas 可以轻松地将这个嵌套的字典结构转换成DataFrame:

sector_total_value_df = pd.DataFrame.from_dict(sector_total_value, orient='index')

使用groupby 拆分应用组合

pandas 使用groupby 方法使这个过程变得非常简单。

拆分

groupby 方法将 DataFrame 按一列或多列(甚至另一个系列)分成组:

grouped_by_sector = sectors_df.groupby('Sector')

grouped_by_sector 类似于我们之前构建的索引,但可以更轻松地操作组,如下面的步骤所示。

申请

要计算每组中的总值,请选择要汇总的列或列,将aggaggregate 方法与您要应用的函数一起使用:

sector_total_value = grouped_by_sector['Current Value'].agg(value_in_sect=sum)

合并

已经完成了! apply 步骤已经创建了一个 DataFrame,其中索引是 Sector(groupby 列),value_in_sect 列中的值是 sum 操作的结果。

我省略了 pct_in_sect 部分,因为 a) 事后更容易完成:

sector_total_value_df['pct_in_sect'] = round(sector_total_value_df['value_in_sect'] / total_value * 100, 2)
sector_total_value_df['value_in_sect'] = round(sector_total_value_df['value_in_sect'], 2)

和b)它超出了这个答案的范围。

大部分内容都可以在一行中轻松完成(参见脚注 2 以了解百分比和四舍五入):

sector_total_value_df = sectors_df.groupby('Sector')['Current Value'].agg(value_in_sect=sum)

对于子行业,还有一个额外的考虑因素,那就是分组应该由行业子行业完成,而不仅仅是子行业,这样,例如来自公用事业/天然气和能源/天然气的行t 合并。

subsector_total_value_df = sectors_df.groupby(['Sector', 'Sub Sector'])['Current Value'].agg(value_in_sect=sum)

这会生成一个带有 MultiIndex 的 DataFrame,它具有“Sector”和“Sub Sector”级别,以及“value_in_sect”列。对于最后一个魔法,可以很容易地计算出 Sector 中的百分比:

subsector_total_value_df['pct_within_sect'] = round(subsector_total_value_df['value_in_sect'] / sector_total_value_df['value_in_sect'] * 100, 2)

之所以有效,是因为在划分期间匹配了“扇区”索引级别。

脚注 1. 这与您的代码略有不同,因为我选择使用未四舍五入的总值计算百分比,以最大限度地减少百分比误差。但理想情况下,舍入仅在显示时进行。

脚注 2. 这个单行生成所需的结果,包括百分比和四舍五入:

sector_total_value_df = sectors_df.groupby('Sector')['Current Value'].agg(
    value_in_sect = lambda c: round(sum(c), 2),
    pct_in_sect = lambda c: round(sum(c)/sectors_df['Current Value'].sum() * 100, 2),
)

【讨论】:

  • 不幸的是,当我只是将这一行复制并粘贴到终端时,我得到的只是一个具有 3 列(索引、sect 中的值和 sect 中的 pct)和一行的数据框。我还没来得及真正看这个回复,但我会在弄清楚问题后回复你!感谢您的回答和解释!
猜你喜欢
  • 2020-08-14
  • 2019-04-24
  • 2018-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多