检查数字是否根据另一列是连续的?

时间:2019-07-31 09:14:37

标签: python pandas logic

我有一个看起来像这样的数据框:

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

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

我想编写一个代码,返回根据上述逻辑需要添加的缺少数字。

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

也许逻辑上有些失败?

谢谢

2 个答案:

答案 0 :(得分: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]

答案 1 :(得分:0)

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

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

代码在这里:

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