【问题标题】:Comparing multiple columns to a list with multiple values将多列与具有多个值的列表进行比较
【发布时间】:2022-01-09 20:43:40
【问题描述】:

我有这个数据。

df1 = pd.DataFrame({"user": [1942,  95870, 85228,  6636],
                   "0": [1524, 8788, 9899, 27172],
                   "1": [1333, 4476, 78783, 90832],
                   "2": [2021, 2022, 34522, 38479]})
df1.set_index(df1['user'])
print(df1)

    user      0      1      2
0   1942   1524   1333   2021
1  95870   8788   4476   2022
2  85228   9899  78783  34522
3   6636  27172  90832  38479

df1df2 的行数相同(实际数据为 100 万),df2 的每一行由 方括号 中的多个数字组成,用逗号分隔为如下:

df2 = pd.DataFrame({
                   "0": [[1123, 2021, 8788]]})

方括号中的数字从 1 到 20 不等,在本例中只有 3。但是,df2df1 的数字行是相同的。

print(df2)
           0
0  [1123, 2021, 8788]

我想做的是从df1 中选择一个用户,例如user1942 并比较该行(1524, 1333, 2021) 中的三个数字中的任何一个是否在df2 @987654332 中的任何相应方括号中@。如果为 True,则为布尔值 1,否则为 0,或任何其他表示形式都会有所帮助。

更新:应该逐行比较。这是df1 中的一行,而不是df2 中的相应行。

输出可能看起来像这样,或者更接近: 输出:因为 2021 在 df2 中,所以答案是 True。然后移动到df1中的下一个用户,将该用户的3个数字与df2中对应的行号进行比较,等等。

user      status
1942        1
...

我知道有很多关于比较多列的问题,但我找不到可重现或类似于此上下文的内容。

【问题讨论】:

  • 不清楚,要一个一个做这个吗?或同时为所有行。另外,你只显示了 df2 的 1 行,如果你有很多会发生什么?请更新您的问题以澄清这种歧义。
  • 我已添加更新以澄清您的问题。再次确认,df2 中的行很多,与df1 大小相同,因此在某种意义上可以将比较视为“成对”。不幸的是,我无法为df2 生成更多行,但我希望这个想法很明确。
  • @SquidGame 每行的df1df2 中是否总是有唯一的数字?
  • @ShubhamSharma 一些数字是唯一的,但其他数字不是,我正在做的是比较df 行中的任何数字是否在df2 中的任何数字中。某些数字可能会在df2 中重复,因为它们是通过预测函数获得的。我希望这能澄清你的问题。

标签: python pandas dataframe for-loop compare


【解决方案1】:

假设 df1 的索引与 df2 的索引相同,并且两者的行之间的关系是 1:1,我会这样做:

df3 = pd.DataFrame()
  for index, row in df1.iterrows():
  to_find = [row[1], row[2], row[3]]
  to_check = df2.iloc[index][0]
  if [True for i in to_find if i in to_check]:
    df3 = df3.append([1])
  else:
    df3 = df3.append([0])

您为 df1 中的值创建一个列表,然后检查是否有任何值出现在相应 df2 行的列表中,如果至少一个值匹配,则将 1 附加到结果 df3,否则为 0。 始终假设您的关系是 1:1,现在在 df3 中,您拥有与所选用户对应的索引和用于验证匹配的布尔值。

编辑:改进 Daniele 的解决方案以允许对整数进行迭代

df3 = pd.DataFrame()
for index, row in df1.iterrows():
    to_find = [row[0], row[1], row[2], row[3]]
    to_check = df2.iloc[index][0]
    to_numpy = np.array([to_check])
    to_list  = to_numpy.tolist()
    if [True for i in to_find if i in to_list]:
        df3 = df3.append([1])
    else:
        df3 = df3.append([0])

【讨论】:

  • 解决方案在此行产生错误TypeError: argument of type 'int' is not iterableif [True for i in to_find if i in to_check]:。我可以确认to_findto_check 包含正确的int 值。你建议我在哪里修改?
  • 如果您尝试迭代单个元素(在这种情况下为 int),则会发生此错误,老实说,我在尝试时没有收到此错误。您确定将其正确集成到您的代码中吗?
  • 也许在您的 df2 中有一些行包含单个 int 值而不是列表,从而产生了这种行为
  • 您好,我接受了您的更改,现在可以使用了吗?我认为您提供的示例的数据类型不正确,因为我使用了以前的代码,请告诉我!
  • 是的,它有效。真实数据有一​​些行只有一个值导致错误,现在它可以工作,无论在一行中比较值的数量。
【解决方案2】:

我还没有找到一个不依赖 for 循环的非常优雅的解决方案,但是如果我们首先将数据帧转换为 np.arrays(甚至列表),我们可以获得一个非常好的解决方法。 首先,我们操作df1来获取有组织的记录

import pandas as pd
import numpy as np

df1 = pd.DataFrame({"user": [1123,  95870, 85228,  6636],
                   "0": [1524, 8788, 9899, 27172],
                   "1": [1333, 4476, 78783, 90832],
                   "2": [2021, 2022, 34522, 38479]})
df1 = df1.set_index('user', drop=True)
print(df1)
           0      1      2
user                      
1123    1524   1333   2021
95870   8788   4476   2022
85228   9899  78783  34522
6636   27172  90832  38479

然后,我们对df2 执行相同的操作。即使两个数据帧的列数不同,所提出的方法也有效。

df2 = pd.DataFrame([[1123, 2021, 8788, 6636],
                    [1333, 2023, 4477, 78783],
                    [1524, 2023, 9899, 27172],
                    [2021, 2023, 345233,38479]]
                    )

df2 = pd.DataFrame(df2.to_numpy().tolist())
df2 = df2.set_axis(df1.index, axis=0)
print(df2)
          0     1       2      3
user                            
1123   1123  1333    8788   6636
95870  1333  2023    4477  78783
85228  1524  2023    9899  27172
6636   2021  2023  345233  38479

最后,我们使用列表推导生成所需的值,该列表推导遍历行以检查它们是否具有共同的元素。

inter = [np.isin(arr[0], arr[1]).any() for arr in zip(df1.to_numpy(), df2.to_numpy())]
print(inter)
[True, False, True, True]

【讨论】:

  • 这个解决方案不完全是我问的,如果我的问题不清楚,我可以详细说明。 df2 没有像您的情况那样的单独列,但它是具有 square brackets 中的值的单个列,例如 [1123, 2021, 8788]。此外,您的解决方案似乎是检查df1 中的每一行与df2 中的一列。我希望这有助于澄清问题,否则我可能会误解您的解决方案@saiden
  • 那么df2是这样的吗? pd.DataFrame({"0": [[1123, 2021, 8788], [2021, 95870, 4476]]})
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
相关资源
最近更新 更多