【问题标题】:join and groupby 2 dataframes加入和分组 2 个数据帧
【发布时间】:2021-12-13 15:28:43
【问题描述】:

我有 2 个数据框

df:ServicesA                         df:ServicesB
index      clientID    ServiceID_A  |  index    ClientID  ServiceID_B
0          A                 1      |  0          A           4
1          B                 2      |  1          B           5
2          C                 3      |  2          D           6
2          B                 4      |  

我想获得一个新的 df,在 df:ServicesB 上显示这些客户以及这些客户拥有多少个 servicesA。会是这样的

index    ClientID With ServiceID_B        count(ServiceID_A)
0                   A                             1
1                   B                             2
2                   D                             0

我试过这个:

我从 df:ServicesB 获得了一个唯一的客户端 ID 列表,并创建了一个名为“df”的新 df

df = pd.DataFrame(df_ServicesB['Client ID', ].unique(),columns=['Client ID'])

然后我使用这个 lambda 函数,该函数将从 df 获取每个客户端 id 并遍历 df:ServicesA 计算具有数学的客户端 id 的那些行(这相当于计算该数据帧上的 serviceidA

def getTotaldfServicesA(clientid):
  total_services = 0
  for index, row in df_ServicesA.iterrows():
    if row['ClientID'] == clientid:
      total_services += 1
  return total_services

df['Total_servicesA'] = df.apply(lambda row: getTotaldfServicesA(row['ClientID']),axis=1)

我“相信”该公式有效,但我说“我相信”,因为从技术上讲,我没有看到生成的 df,因为 df_ServicesA 是一个很长的迭代列表,而且 df_ServicesB 上的客户端数量也很长,使得迭代过程指数到 lambda 函数已经运行了几次,但要么失败而没有错误,要么在一夜之间超时,当我到达我的计算机查看结果时,我已经断开连接。目前它已经运行了 4 个小时,但我仍然没有得到结果 df 数据集/帧。

也许有更 Pythonic 的方式来做到这一点?或者也许是一种提高效率的方法,这样它就不会永远花费?

提前谢谢你

【问题讨论】:

    标签: python pandas dataframe google-colaboratory


    【解决方案1】:

    给你: 我用 csv 文件测试了你的日期框架,它的工作原理:

    sA = pd.read_csv("ServicesA.csv")
    sB = pd.read_csv("ServicesB.csv")
    count_dict = sA.groupby(['ClientID']).size().to_dict()
    count_dict.setdefault('D',0)
    sB['count(ServiceID_A)'] = sB.ClientID.replace(count_dict)
    

    如果这不起作用,请告诉我

    【讨论】:

    • 嗨,Saravanan,非常感谢您帮助我。在我根据我的特定代码和名称约定调整您的答案后,我收到此错误:TypeError: Cannot compare types 'ndarray(dtype=int64)' and 'str' should cast or coercion of some sort?
    • 把你的ClientID变量转换成Object然后试试。
    【解决方案2】:

    您应该始终避免迭代 DataFrame/ Series,它非常慢。它应该是你最后的资源。几乎总是有更好的方法。 在这种情况下,您需要查看groupbymerge。 您应该阅读这些指南

    1. https://pandas.pydata.org/docs/user_guide/groupby.html
    2. https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html

    这会比使用iterrows快得多

    >>> res = (
          df_ServicesB.merge(df_ServicesA, how='left', on='ClientID')
                      .groupby('ClientID', as_index=False)
                      [['ServiceID_A']].count()      
    )
    >>> res.columns = ["ClientID With ServiceID_B", "count(ServiceID_A)"]
    >>> res
    
      ClientID With ServiceID_B  count(ServiceID_A)
    0                         A                   1
    1                         B                   2
    2                         D                   0
    

    【讨论】:

    • 感谢 Harry 提供有关何时使用迭代的信息,我知道这并不理想,但总的来说,我几乎是 pandas 和 python 的新手,所以我非常感谢您的意见。我确实设法让您的代码与我的数据集一起使用,但是有些方法是如何使用服务 B 为每个客户端复制服务 A 的总数。我可能需要提到两个数据集/框架都有一个或多个属于同一客户端的服务身份证。
    【解决方案3】:

    您可以对您的第一个数据帧进行分组并计算组数:

    # Assuming that df:ServicesA is df_a
    grouped = df_a.groupby("clientID").count()
    >>> grouped
    
            ServiceID_A
    clientID    
           A    1
           B    2
           C    1
    

    之后,您可以使用merge 函数将第二个数据框从外部连接到分组中:

    # Assuming that df:ServicesB is df_b
    joined = df_b[["ClientID"]].merge(grouped, left_on="ClientID",
                                      right_on="clientID", how="left").fillna(0)
    >>> joined
        clientID    ServiceID_A
    0          A            1.0
    1          B            2.0
    2          D            0.0
    

    【讨论】:

    • 你得到了我接受的答案,伙计.. 非常感谢! :)。对我来说,按照您的建议分两步完成它是有意义的,并且在我设法使您的方法适应我的数据集之后,我得到了我想要的结果 df。再次。非常感谢:)
    猜你喜欢
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    相关资源
    最近更新 更多