Python Pandas - 计算总均值,按字段分组,然后计算分组均值并追加。

3

假设我有一个包含“dir”和“speed”两列的pd.DataFrame:

import pandas as pd
df = pd.DataFrame({'dir': ['fwd', 'fwd', 'fwd', 'bwd', 'bwd'],
                  'speed': [10, 5, 1, 6, 8]})

# or with more columns:
df = pd.DataFrame({'dir': ['fwd', 'fwd', 'fwd', 'bwd', 'bwd'],
                  'speed': [10, 5, 1, 6, 8],
                  'mass': [100, 200, 100, 500, 300]})

   dir  speed

0  fwd     10

1  fwd      5

2  fwd      1

3  bwd      6

4  bwd      8

我试图计算3个值,结果是一个包含“median_speed”,“median_fwd_speed”和“median_bwd_speed”的1行DataFrame。
我对Pandas非常陌生,请原谅我的错误。此外,我还有很多其他的计算,所以保留agg肯定更可取,但是去掉np.where()会更好。
目前为止,我的代码如下:
# duplicate dir column for future referencing
df['dir2'] = df['dir']

# groupby and calc median for fwd and bwd
df = df.groupby('dir').agg({"dir2": lambda x: x.iloc[0], # how do I do nothing with agg?
                            "speed": "median"})

# grab forward and bwd fields
df['median_fwd_speed'] = np.where(df['dir2'] == 'fwd', df['speed'], 0)
df['median_bwd_speed'] = np.where(df['dir2'] == 'bwd', df['speed'], 0)

输出:

    dir2  speed  median_fwd_speed  median_bwd_speed

dir                                                

bwd  bwd    7.0               0.0               7.0

fwd  fwd    5.0               5.0               0.0

当然,输出不止一行,并且不包含总中位数。任何帮助将不胜感激!
我可能可以使用 `df["speed"].median()` 并将其存储为变量,但是否有一种优雅的方法只使用 groupby 和 agg?
多列的预期输出结果应该类似于:
median_speed    fwd_median_speed    bwd_median_speed    median_mass    fwd_median_mass    bwd_median_mass
6               5                   7                   200            100                400

你能否在示例数据的多个列中添加预期输出? - jezrael
@jezrael已添加到问题的末尾。谢谢 - Frankfurters
4个回答

1
您可以聚合中位数,然后为中位数添加新列:
f = lambda x: f'median_{x}_speed'  
df1=df.groupby('dir')[['speed']].median().rename(f).T.assign(median = df['speed'].median())
print (df1)
dir    median_bwd_speed  median_fwd_speed  median
speed                 7                 5     6.0

编辑:如果需要多列,请使用以下方法:

cols = ['speed', 'mass']
df1=(df.groupby('dir')[cols]
       .median()
       .T
       .assign(median = df[cols].median())
       .stack()
       .to_frame()
       .T 
       )
df1.columns = df1.columns.map(lambda x: f'{x[1]}_{x[0]}')
print (df1)
   bwd_speed  fwd_speed  median_speed  bwd_mass  fwd_mass  median_mass
0        7.0        5.0           6.0     400.0     100.0        200.0

感谢您的帮助。由于我实际上有多列,因此使用agg,我该如何将其纳入您的解决方案?我已经在问题中添加了一个新的“mass”列示例。 - Frankfurters
@Frankfurters - 答案已被编辑。 - jezrael

1

类似这样的东西应该可以工作


(df.groupby('dir')['speed']
    .agg('median')
    .append(pd.Series(index = ['total'], data = df['speed'].median()))
    .to_frame()
    .T
)

输出:


    bwd fwd total
0   7.0 5.0 6.0

如果您需要,您可以使用.rename(columns = ...)方法进一步重命名列。

编辑

如果有多个列,这应该可以工作。

(df.groupby('dir')
    .agg('median')
    .append(df.median().rename('total') )
    .unstack()
    .to_frame()
    .T
)

输出


    speed           mass
dir bwd fwd total   bwd fwd     total
0   7.0 5.0 6.0 400.0   100.0   200.0

感谢您的帮助。由于我实际上有多列数据,因此使用agg函数,您能告诉我如何将其纳入您的解决方案中吗?我已经在问题描述中添加了一个新的“mass”列的示例。 - Frankfurters
edited -- pls take a look - piterbarg
看起来很不错!我使用了df.columns=['a', 'b', 'c', 'd', 'e', 'f']来重命名列并删除堆叠的列名。但是它也给了我一个弃用警告:FutureWarning: Dropping of nuisance columns in DataFrame reductions (with 'numeric_only=None') is deprecated; in a future version this will raise TypeError. Select only valid columns before calling the reduction. 引用.append(df.median().rename('total')) - Frankfurters
不确定它来自哪里 - 我没有理解。不用担心。但是重命名列更规范的方法是使用.rename函数,就像@jezrael答案中所示。 - piterbarg

0
我会提取每个值,将它们放入列表中并将列表转换为DataFrame,这样这些值就可以在单个行中表示。
metrics = [
    df[df['dir'=='fwd']]['speed'].median()
    df[df['dir'=='bwd']]['speed'].median()
    df['speed'].median()
]

pd.DataFrame([metrics], columns=['median_fwd', 'median_bwd', 'median_speed'])

谢谢您的帮助,但不幸的是我有很多值需要计算,手动为其中的50个输入这些语句可能不是一个好主意。 - Frankfurters

0

你需要创建一个单独的数据框来保存结果。你可以通过两个操作得到中位数:直接中位数和按组分组的中位数:

pd.DataFrame([[df['speed'].median(), *df.groupby('dir')['speed'].median()]],
             columns=['median_speed', 'median_bwd_speed', 'median_fwd_speed'])

如果有更多的列,您可以进行操作

cols = ['speed', 'mass']
pd.DataFrame([[*df[cols].median(), *np.ravel(df.groupby('dir')[cols].median())]],
             columns=[f'median_{i}{j}' for i in ['', 'fwd_', 'bwd_'] for j in cols])

谢谢您的帮助。由于我的数据有多列,因此我使用了agg函数,您能帮我将您的解决方案应用到我的数据上吗?我在问题中添加了一个新的“mass”列作为示例。 - Frankfurters
@Frankfurters。您只需将“mass”添加到列中即可。 - Mad Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接