python - Pandas:在不同列上给定一个参考值,对列进行行操作
问题描述
我正在使用如下所示的数据库。对于每种水果(为简洁起见,以下仅是苹果和梨),我们有:1. 年销售额,2. 当前销售额,3. 月销售额和 4. 销售额的标准差。它们的顺序可能会有所不同,但每个水果总是有 4 个值。
dataset = {'apple_yearly_avg': [57],
'apple_sales': [100],
'apple_monthly_avg':[80],
'apple_st_dev': [12],
'pears_monthly_avg': [33],
'pears_yearly_avg': [35],
'pears_sales': [40],
'pears_st_dev':[8]}
df = pd.DataFrame(dataset).T#tranpose
df = df.reset_index()#clear index
df.columns = (['Description', 'Value'])#name 2 columns
我想执行两组操作。
对于第一组操作,我们分离出一个水果价格,比如“梨”,然后从当前销售额中减去每个平均销售额。
df_pear = df[df.loc[:, 'Description'].str.contains('pear')]
df_pear['temp'] = df_pear['Value'].where(df_pear.Description.str.contains('sales')).bfill()
df_pear ['some_op'] = df_pear['Value'] - df_pear['temp']
上述工作通过创建一个临时列来保存 pear_sales 为 40,回填它,然后用它来减去值。
问题1:有没有更简洁的方法可以在没有临时数组的情况下执行此操作?此外,我确实得到了一个常见的警告,说我应该使用 '.loc[row_indexer, col_indexer],即使输出仍然有效。
对于第二组操作,我需要将等于“new_purchases”的“5”行添加到数据框的底部,然后用 sales * (1 + std_dev *some_multiplier) 填充 df_pear['some_op']。
df_pear['temp2'] = df_pear['Value'].where(df_pear['Description'].str.contains('st_dev')).bfill()
new_purchases = 5
for i in range(new_purchases):
df_pear = df_pear.append(df_pear.iloc[-1])#appends 5 copies of the last row
counter = 1
for i in range(len(df_pear)-1, len(df_pear)-new_purchases, -1):#backward loop from the bottom
df_pear.some_op.iloc[i] = df_pear['temp'].iloc[0] * (1 + df_pear['temp2'].iloc[i] * counter)
counter += 1
这个“向后”循环实现了它,但是我再次担心可读性,因为创建了另一个临时列,然后索引相当难看?
谢谢你。
解决方案
我认为,有一种更清洁的方法可以一次性完成这两项任务:
添加 2 列Fruit和Descr ,在第一个“_”处拆分Description的结果:
df[['Fruit', 'Descr']] = df['Description'].str.split('_', n=1, expand=True)
要查看结果,您现在可以打印df。
定义以下函数来“重新格式化”当前组:
def reformat(grp): wrk = grp.set_index('Descr') sal = wrk.at['sales', 'Value'] dev = wrk.at['st_dev', 'Value'] avg = wrk.at['yearly_avg', 'Value'] # Subtract (yearly) average wrk['some_op'] = wrk.Value - avg # New rows wrk2 = pd.DataFrame([wrk.loc['st_dev']] * 5).assign( some_op=[ sal * (1 + dev * i) for i in range(5, 0, -1) ]) return pd.concat([wrk, wrk2]) # Old and new rows
将此函数应用于按Fruit分组的每个组,删除Fruit 列并将结果保存回df:
df = df.groupby('Fruit').apply(reformat)\ .reset_index(drop=True).drop(columns='Fruit')
现在,当你print(df)
,结果是:
Description Value some_op
0 apple_yearly_avg 57 0
1 apple_sales 100 43
2 apple_monthly_avg 80 23
3 apple_st_dev 12 -45
4 apple_st_dev 12 6100
5 apple_st_dev 12 4900
6 apple_st_dev 12 3700
7 apple_st_dev 12 2500
8 apple_st_dev 12 1300
9 pears_monthly_avg 33 -2
10 pears_sales 40 5
11 pears_yearly_avg 35 0
12 pears_st_dev 8 -27
13 pears_st_dev 8 1640
14 pears_st_dev 8 1320
15 pears_st_dev 8 1000
16 pears_st_dev 8 680
17 pears_st_dev 8 360
编辑
我怀疑描述是否也应该从“st_dev”行复制到新行。如果您想要那里的其他内容,请在创建wrk2 后将其设置为重新格式化功能。
推荐阅读
- javascript - 隐藏/显示独立 div 的 li 元素
- javascript - How can i remove NaN values between increments in my counter?
- neo4j - UNION optional match node identifiers without collect/unwind (because unwind keeps unbinding preceding identifiers)
- python - 需要拆分具有混合数据的列
- python - 使用 Python 和 BeautifulSoup 抓取 Ebay 网页
- jspdf - Tabulator pdf download formatting
- r - 用 igraph 计算密度 - 为什么 igraph 会更改传递的邻接矩阵?
- java - 在 Java 中(在 Intel CPU 上)对许多短字符串值进行 SHA-256 编码的最快方法是什么?
- android - 我应该在应用内购买后使用本地数据库并切换到 Firestore 吗?
- flutter - Flutter:LayoutBuilder 中的 SliverAppBar