【问题标题】:What is the ideal way of filtering one pandas dataframe with the help of the columns of another dataframe?借助另一个数据框的列过滤一个熊猫数据框的理想方法是什么?
【发布时间】:2019-06-17 12:05:11
【问题描述】:
import numpy as np
import pandas as pd

df1 = pd.DataFrame({"id": ["s1", "s2", "s3"],"threshold": [1, 2, 7]})
df2 = pd.DataFrame({"id": ["s1", "s1", "s1", "s2", "s2", "s3", "s3", "s3", "s5", "s5"], "value": [2, -1, 1, -3, 3, 3, 4, 2, 1, 6]})

我想在我的数据框 df1 中添加一列,这样:

  • df1["newcolumn"]是,df2中"value"的"sum",
  • 对于df1中的相应id,
  • 其中 df2 中的“值”大于或等于 df1 中定义的“阈值”
  • 对于每个相应的 ID。

例如

  • 对于 df1 中的 id="s1",
  • df2 中有三个“值”(即 2、-1 和 1),
  • 在 df2 中的这些“值”中,只有 2 和 1 大于或等于 df1 中为 s1 定义的“阈值”(即 1)
  • 所以,代码应该为 s1 返回 2+1 = 3,
  • 以类似的方式,它应该为 s2 返回 3,
  • 以类似的方式,它应该为 s3 返回 0,
  • 以类似的方式,它应该返回,大概是 s5 的 NaN

我知道我也可以通过循环处理这个计算。

df1['my_stat_column'] = 0 # initialize

for i in range(0, df1.shape[0]):
    s = df1.iloc[i]['id']
    t = df1.iloc[i]['threshold']

    for v in range(0, df2.shape[0]):          
        non_pythonic_and_stupid_way = df2[ (df2['id']==s) & (df2['value']>=t)]
        my_stat_value = non_pythonic_and_stupid_way['value'].sum()
        df1.iloc[i]['my_stat_column'] = my_stat

df1.head()

那么,通过另一个数据帧的列过滤一个 Pandas 数据帧的真正方法是什么?

谢谢!

【问题讨论】:

  • 在示例中,您的值是有意为之的字符串?
  • 我编辑了这个错误。感谢您指出这一点。

标签: python pandas dataframe


【解决方案1】:

从您的帖子来看,df1.thresholddf2.value 都应该是数字:

df2.value = pd.to_numeric(df2.value)
df1.threshold = pd.to_numeric(df1.threshold)

由于我们正在使用对齐的id,因此最好将它们设为索引:

df1.set_index('id', inplace=True)
df2.set_index('id', inplace=True)

那么df1.id应该只有唯一值,所以,我们可以先标记所有大于等于阈值的值:

df2['valid'] = df2.value.ge(df1.threshold)

df2['valid'] = df2.value * df2['valid']

然后你可以做一个简单的groupby:

df1['newcolumn'] = df2.groupby('id').valid.sum()

输出:

    threshold  newcolumn
id                      
s1          1          3
s2          2          3
s3          7          0

选项2:您可以使用merger(将列转换为数字后),而不是将id设置为索引:

new_df = df2.merge(df1, on='id', how='outer')

# similar to above, in one step
new_df['valid'] = new_df.value.ge(new_df.threshold) * new_df.value

# then groupby:
new_df.groupby('id').valid.sum()

给予:

id
s1    3
s2    3
s3    0
s5    0
Name: valid, dtype: int64

【讨论】:

    【解决方案2】:

    如果您正在寻找更短的代码,这是我的答案

    df1['my_stat_column'] = [df2[df2.id == i][df2[df2.id == i].value >= t].value.sum() for _,i,t in df1.itertuples()]
    

    我认为在 python 中没有一种“真正”的方式来做任何事情。有很多方法,您需要根据您的应用程序找到最有效的方法或最易读的方法等

    【讨论】:

      猜你喜欢
      • 2014-12-27
      • 1970-01-01
      • 2022-01-23
      • 2023-04-03
      • 1970-01-01
      • 2021-07-15
      • 2023-01-12
      • 1970-01-01
      • 2021-10-31
      相关资源
      最近更新 更多