2

我有一个多年的每日数据框,它在不同的年份(Col2)中存在不同的实体(Col1)。我正在尝试过滤数据框,使其仅保留在每个指定年份中具有值的那些行。(我从日期时间索引创建了 Col2 认为它会使过滤过程更容易)

换句话说,我正在尝试设计一个条件过滤器,其中保留满足另一列条件的列值。

这是我的数据框:

Date    Col1 Col2 Col3 Col4
1/1/16  M   2016  34  a
2/2/16  M   2016  35  f
3/3/16  M   2016  45  d
1/1/17  S   2017  66  ff
2/2/17  S   2017  66  mn
1/1/18  T   2018  78  jh
2/2/18  T   2018  789  kk
1/1/17  M   2017  100  f
2/2/17  S   2017  2020 jj
2/2/18  M   2018  3005 m

实体 M、S 和 T 在 2016-2019 年记录了价值,但只有 M 在所有三年中都有价值。

因此,生成的数据框应如下所示:

Date    Col1 Col2 Col3 Col4
1/1/16  M   2016 34   a
2/2/16  M   2016 35   f
3/3/16  M   2016 45   d
1/1/17  M   2017 100  f
2/2/18  M   2018 3005 m

我正在尝试通过以下代码行来计算逻辑,但没有任何工作:

(1)
    years = [2016,2017,2018]
    
for station in df_in['Col1']:
    years = [2016,2017,2018]
    if df_in['Col2'].isin(years).any():
        df = df_in
    else:
        df = df_in.drop(df_in[df_in.Col1].index)

或者

(2)
df= df_in['Col1'].apply(lambda x: x in df_in['year'].isin(years))

或者

(3)
df = df_in.loc[(df_in['Col1']) & (df_in['Col2'].isin(years))]

什么是实现这一目标的好方法?

任何帮助都感激不尽。

4

3 回答 3

1

如果需要仅比较years 列表中的值,则比较GroupBy.transform掩码中相等的集合,然后过滤boolean indexing

years = [2016,2017,2018]
df1 = df[df.groupby('Col1')['Col2'].transform(lambda x: set(x) == set(years))]
print (df1)
     Date Col1  Col2  Col3 Col4
0  1/1/16    M  2016    34    a
1  2/2/16    M  2016    35    f
2  3/3/16    M  2016    45    d
7  1/1/17    M  2017   100    f
9  2/2/18    M  2018  3005    m

如果要比较列表中的现有值,并且每组可能有一些其他值比较高或相等:

print (df)
     Date Col1  Col2  Col3 Col4
0  1/1/16    M  2019    34    a <- 2019
1  2/2/16    M  2016    35    f
2  3/3/16    M  2016    45    d
3  1/1/17    S  2017    66   ff
4  2/2/17    S  2017    66   mn
5  1/1/18    T  2018    78   jh
6  2/2/18    T  2018   789   kk
7  1/1/17    M  2017   100    f
8  2/2/17    S  2017  2020   jj
9  2/2/18    M  2018  3005    m

years = [2016,2017,2018]
df1 = df[df.groupby('Col1')['Col2'].transform(lambda x: set(x) >= set(years))]
print (df1)
     Date Col1  Col2  Col3 Col4
0  1/1/16    M  2019    34    a
1  2/2/16    M  2016    35    f
2  3/3/16    M  2016    45    d
7  1/1/17    M  2017   100    f
9  2/2/18    M  2018  3005    m
于 2020-07-03T13:27:11.583 回答
1

filter+检查groupby

s=df.groupby('Col1').filter(lambda x : pd.Series([2016,2017,2018]).isin(x['Col2']).all())
     Date Col1  Col2
0  1/1/16    M  2016
1  2/2/16    M  2016
2  3/3/16    M  2016
7  1/1/17    M  2017
9  2/2/18    M  2018
于 2020-07-03T13:26:35.587 回答
0

如果你不想硬连线这些年。请尝试以下 1.将所有独特的年份提取到列表中

  1. Groupby 每年并生成一个列,其中包含 Col1 中每个组中所有年份的列表

3.通过将每个组中的列表转换为一组以消除重复来检查成员资格。与列表 d 相交,如果长度相同,则布尔选择

    d=df.Col2.unique().tolist()
    df2=df.groupby(['Col1']).Col2.agg(list).reset_index().rename(columns={'Col2':'Lst'})#
    df[pd.merge(df,df2, how='left', on='Col1').Lst.apply(lambda e:[*{*e}&{*d}]).str.len()==len(d)]#



    Date Col1  Col2
0  1/1/16    M  2016
1  2/2/16    M  2016
2  3/3/16    M  2016
7  1/1/17    M  2017
9  2/2/18    M  2018

%%timeit 
d=df.Col2.unique().tolist()
df2=df.groupby(['Col1']).Col2.agg(list).reset_index().rename(columns={'Col2':'Lst'})
df[pd.merge(df,df2, how='left', on='Col1').Lst.apply(lambda e:[*{*e}&{*d}]).str.len()==len(d)]
7.5 ms ± 45.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
于 2020-07-03T14:12:19.187 回答