【问题标题】:Consolidating panda dataframes: Choose the smaller absolute value合并熊猫数据框:选择较小的绝对值
【发布时间】:2019-08-31 14:55:02
【问题描述】:

我有两个熊猫数据框:

数据框 A:

date        ticker  return
2017-01-03  CRM     0.018040121229614625
2017-01-03  MSFT    -0.0033444816053511683
2017-01-04  CRM     0.024198086662915008
2017-01-04  MSFT    -0.0028809218950064386
2017-01-05  CRM     -0.0002746875429199269
2017-01-05  MSFT    0.0017687731146487362

数据框 B:

date        ticker  return
2017-01-03  CRM     0.018040120991250852
2017-01-03  MSFT    -0.003344466975803595
2017-01-04  CRM     0.024198103213211475
2017-01-04  MSFT    -0.0028809268004892363
2017-01-05  CRM     -0.00027464144673694513
2017-01-05  MSFT    0.0017687829680113065

现在我需要第三个“整合”数据框:

  • 列名相同
  • 对于每一行,我必须从 DataframeA 或 DataframeB 中选择绝对值较小的“返回”数据

有什么建议吗?

【问题讨论】:

  • please don't put images of code or data in the question,而是将它们作为文本发布,以便人们可以重现您的问题
  • 我刚刚改正了
  • 谢谢,(pd.concat((A,B),ignore_index=True).groupby(['date','ticker'])['return'] .apply(lambda x: x.abs().min()).reset_index())?
  • 差不多。您正在用 abs 值填充新熊猫。那不是我需要的。我需要用绝对值较小的 dataframeA 或 dataframeB 'return' 列填充它。

标签: python python-3.x pandas dataframe absolute-value


【解决方案1】:

这是使用可运行代码编辑的新答案

即使行数不相等,以下代码也将起作用。它将首先在两个数据帧上采用公共行,然后为所需列找到正确的值

import numpy as np
import pandas as pd

## creating dummy data to get runable code
## ---------------------------------------
n_rows = 20
sub_categories = np.random.choice(4, size=n_rows)
dic1 = {
    "a": list(range(n_rows)),
    "b": sub_categories,
    "c": np.random.randn(n_rows)
}

dic2 = {
    "a": range(n_rows),
    "b": sub_categories,
    "c": np.random.randn(n_rows)
}

df1 = pd.DataFrame(dic1)
df1.drop(index=list(np.random.choice(n_rows, 5, replace=False)), inplace=True)

df2 = pd.DataFrame(dic2)
df2.drop(index=list(np.random.choice(n_rows, 3, replace=False)), inplace=True)




## Main Answer
## ---------------------------------------------------------


## merge df1 and df2 then create new column c based which take min(abs(c_1, c_2))

result = df1.merge(df2, how="inner", on=["a","b"], suffixes=["_1", "_2"]).copy()
result["c"] = result["c_1"].where(np.abs(result["c_1"])<np.abs(result["c_2"]), 
                                   result["c_2"], axis=0)
display(result)

## finally reindex to remove extra columns
result = result.reindex(columns=["a","b","c"])
result


旧答案

您可以执行以下操作

series = df1["return"].where(np.abs(df1["return"])<np.abs(df2["return"]), df2["return"], axis=0)
series

如果返回的绝对值小于 df2 中的同一行,它将返回连续值取自 df1 的系列,否则它将取自 df2 的值

然后您可以替换 df1 或 df2 的列或它们的副本以获取您想要的数据框

df1["return"] = series

【讨论】:

  • 你可以做df1["return"]=np.where(np.abs(df1["return"])&lt;np.abs(df2["return"]), df2["return"], df1["return"])。这将直接将系列分配给数据框中的列。
  • 没错,为了清楚起见,我只是分两步打破了它
  • 如果我在 dataframeA 和 dataframeB 中的行数相同,它就可以工作。如何获取它如果我在 dataframeA 中有一些在 dataframeB 中不存在的行?非常感谢
  • @user2132478 请检查上面已编辑的答案,现在即使行数不同,它也应该可以工作,:) 如果它有效,请不要忘记标记已解决
【解决方案2】:

您可以使用concat 加入dataframe,然后使用groupbyticker 分组,并获得每个组的最小值:

df3=pd.concat([df1,df2]).groupby('ticker').min().reset_index()

【讨论】:

  • 您还必须在 groupby 中包含日期。此外,OP 想要绝对最小值。
【解决方案3】:

return 上尝试concat+groupby 并返回minkey=abs

(pd.concat((A,B),ignore_index=True)
   .groupby(['date','ticker'])['return'].min(key=abs).reset_index())

         date ticker    return
0  2017-01-03    CRM  0.018040
1  2017-01-03   MSFT -0.003344
2  2017-01-04    CRM  0.024198
3  2017-01-04   MSFT -0.002881
4  2017-01-05    CRM -0.000275
5  2017-01-05   MSFT  0.001769

【讨论】:

  • 如果我有第二列,我是否必须对每一列重复操作?还是可以在同一行完成?
猜你喜欢
  • 2019-06-29
  • 2019-01-13
  • 2016-12-08
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多