【问题标题】:Check if numbers are sequential according to another column?根据另一列检查数字是否是连续的?
【发布时间】:2019-07-31 09:14:37
【问题描述】:

我有一个如下所示的数据框:

Numbers             Names
0                     A
1                     A
2                     B
3                     B
4                     C
5                     C
6                     C
8                     D
10                    D

如果“名称”列中的值对于两个数字都相同,我的数字(整数)需要是连续的:例如,在 6 到 8 之间,数字不是连续的,但这很好,因为列“ Names" 从 C 变为 D。但是,在 8 到 10 之间,这是一个问题,因为两行具有相同的值 "Names",但不是连续的。

我想做一个代码,根据上面解释的逻辑返回需要添加的缺失数字。

import itertools as it
import pandas as pd 
df = pd.read_excel("booki.xlsx")

c1 = df['Numbers'].copy()
c2 = df['Names'].copy()


for i in it.chain(range(1,len(c2)-1), range(1,len(c1)-1)):
    b = c2[i]
    c = c2[i+1]
    x = c1[i]
    n = c1[i+1]
    if c == b and n - x > 1:
        print(x+1)

它会打印两次丢失的数字,因此对于示例中的数据框,它将打印:

9
9

但我只想打印:

9

可能是逻辑有问题?

谢谢

【问题讨论】:

  • 你能添加预期的结果吗?
  • 我认为问题出在itertools.chain。你为什么用它?
  • @VictorRuiz 我改编自我在网上找到的解决方案,但基本上是因为我需要为范围使用两个 for 循环,并且 it.chain 让我指定两个范围(因为它是我的两列正在迭代)。但实际上,另一种解决方案会更受欢迎,因为它在 Anaconda 中运行良好,但在 IDLE 中运行良好

标签: python pandas logic


【解决方案1】:

您可以使用groupby('Names') 然后shift 来获取每个组中以下元素之间的差异,然后只选择没有-1 作为差异的元素,并打印它们的以下编号。

试试这个:

import pandas as pd
import numpy as np
from io import StringIO

df = pd.read_csv(StringIO("""
Numbers             Names
0                     A
1                     A
2                     B
3                     B
4                     C
5                     C
6                     C
8                     D
10                    D"""), sep="\s+")

differences = df.groupby('Names', as_index=False).apply(lambda g: g['Numbers'] - g['Numbers'].shift(-1)).fillna(-1).reset_index()
missing_numbers = (df[differences != -1]['Numbers'].dropna()+1).tolist()
print(missing_numbers)

输出:

[9.0]

【讨论】:

  • 如果gap大于1会发生什么?
  • 你是说如果10改成11?输出仍然只有 9,似乎 OPs 代码也在做什么。
  • 对。我不明白这样的:-)
  • 如果预期的输出是打印整个间隙,我们可以很容易地使用差异的值来如此。
【解决方案2】:

我不确定这里是否需要 itertools。这是一种仅使用 pandas 方法的解决方案。

  1. 根据Names 列使用groupby 对数据进行分组
  2. Numbers 列中选择minmax
  3. 定义一个从最小值到最大值的整数范围
  4. merge这个值和子数据框
  5. 使用isna根据缺失值过滤
  6. 返回过滤后的df
  7. 可选:使用reset_index 重新索引列以获得更漂亮的输出

代码如下:

df = pd.DataFrame({"Numbers": [0, 1, 2, 3, 4, 5, 6, 8, 10, 15],
                   "Names": ["A", "A", "B", "B", "C", "C", "C", "D", "D", "D"]})

def select_missing(df):
    # Select min and max values
    min_ = df.Numbers.min()
    max_ = df.Numbers.max()
    # Create integer range
    serie = pd.DataFrame({"Numbers": [i for i in range(min_, max_ + 1)]})
    # Merge with df 
    m = serie.merge(df, on=['Numbers'], how='left')
    # Return rows not matching the equality
    return m[m.isna().any(axis=1)]


# Group the data per Names and apply "select_missing" function
out = df.groupby("Names").apply(select_missing)
print(out)
#          Numbers Names
# Names
# D     1        9   NaN
#       3       11   NaN
#       4       12   NaN
#       5       13   NaN
#       6       14   NaN

out = out[["Numbers"]].reset_index(level=0)
print(out)
#   Names  Numbers
# 1     D        9
# 3     D       11
# 4     D       12
# 5     D       13
# 6     D       14

【讨论】:

  • 非常感谢!但我收到错误 TypeError: 'numpy.float64' 对象不能被解释为整数
  • Numbers 列中有float 吗?
  • 实际上是的,出于某种原因,pandas 将我的 excel 文件 Numbers 列作为浮点数导入 --> 就像数字 2200000109 变成 2.200001e+09
  • 在处理之前,您可以尝试将列numbers 转换为整数:df.Numbers = df.Numbers.astype(int)。符号2.200001e+09 是科学记数法。阅读here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 2020-01-11
  • 2018-12-20
  • 1970-01-01
相关资源
最近更新 更多