【问题标题】:Retain few NA's and drop rest of NA's during Stack operation in Python在 Python 中的 Stack 操作期间保留少量 NA 并删除其余 NA
【发布时间】:2019-07-31 07:44:51
【问题描述】:

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

df2 = pd.DataFrame({'person_id':[1],'H1_date' : ['2006-10-30 00:00:00'], 'H1':[2.3],'H2_date' : ['2016-10-30 00:00:00'], 'H2':[12.3],'H3_date' : ['2026-11-30 00:00:00'], 'H3':[22.3],'H4_date' : ['2106-10-30 00:00:00'], 'H4':[42.3],'H5_date' : [np.nan], 'H5':[np.nan],'H6_date' : ['2006-10-30 00:00:00'], 'H6':[2.3],'H7_date' : [np.nan], 'H7':[2.3],'H8_date' : ['2006-10-30 00:00:00'], 'H8':[np.nan]})

如我上面的截图所示,我的源 datframe (df2) 包含很少的 NA

当我执行df2.stack() 时,我会丢失数据中的所有 NA。

但是,我想为 H7_dateH8 保留 NA,因为它们有对应的值/日期对。对于H7_date,我有一个有效值H7,对于H8,我有对应的H8_date

我只想在两个值 (H5_date,H5) 均为 NA 时删除记录。

请注意,我这里只有几列,而我的真实数据有 150 多列,而且列名事先不知道。

我希望我的输出如下所示没有H5_date,H5,尽管它们是不适用的

【问题讨论】:

  • df2.stack(dropna=False) ?
  • 对不起,这不起作用。我的意思是它仍然保留 H5Date、H5 的 NA 并显示它们。我想删除那些记录
  • melt 方法的两个答案都有效,但对于@Jon Clements 的答案,我对.all.any 方法有点不清楚。所以,我将@tawab_shakeel 答案标记为解决方案。只是很清楚,由于我对 Python 的熟练程度有限,当应用于@Jon Clements 答案时,我无法理解 .any 和 .all 之间的区别。尽管如此,两个答案都给出了预期的输出

标签: python pandas dataframe


【解决方案1】:

试试pd.DataFrame.melt

df = pd.melt(df2, id_vars='person_id', var_name='col', value_name='dates')
df['col2'] = df['col'].str.split("_").str[0]
df['count'] = df.groupby(['col2'])['dates'].transform(pd.Series.count)
df = df[df['count'] != 0]
df.drop(['col2', 'count'], axis=1, inplace=True)
print(df)
    person_id      col                dates
0           1  H1_date  2006-10-30 00:00:00
1           1       H1                  2.3
2           1  H2_date  2016-10-30 00:00:00
3           1       H2                 12.3
4           1  H3_date  2026-11-30 00:00:00
5           1       H3                 22.3
6           1  H4_date  2106-10-30 00:00:00
7           1       H4                 42.3
10          1  H6_date  2006-10-30 00:00:00
11          1       H6                  2.3
12          1  H7_date                  NaN
13          1       H7                  2.3
14          1  H8_date  2006-10-30 00:00:00
15          1       H8                  NaN

【讨论】:

  • 不,这没有帮助。我希望保留少数 NA 并放弃其余的 NA
  • 当然。也等着看你的答案
【解决方案2】:

方法是融化 DF,应用一个标识同一“组”中的列的键(在本例中为 H<some digits>,但您可以根据需要修改它),然后按人和该键分组,过滤这些组那些包含至少一个非NA值的),例如:

开始于:

df = pd.DataFrame({'person_id':[1],'H1_date' : ['2006-10-30 00:00:00'], 'H1':[2.3],'H2_date' : ['2016-10-30 00:00:00'], 'H2':[12.3],'H3_date' : ['2026-11-30 00:00:00'], 'H3':[22.3],'H4_date' : ['2106-10-30 00:00:00'], 'H4':[42.3],'H5_date' : [np.nan], 'H5':[np.nan],'H6_date' : ['2006-10-30 00:00:00'], 'H6':[2.3],'H7_date' : [np.nan], 'H7':[2.3],'H8_date' : ['2006-10-30 00:00:00'], 'H8':[np.nan]})

用途:

df2 = (
    df.melt(id_vars='person_id')
    .assign(_gid=lambda v: v.variable.str.extract('H(\d+)'))
    .groupby(['person_id', '_gid'])
    .filter(lambda g: bool(g.value.any()))
    .drop('_gid', 1)
)

这给了你:

    person_id variable                value
0           1  H1_date  2006-10-30 00:00:00
1           1       H1                  2.3
2           1  H2_date  2016-10-30 00:00:00
3           1       H2                 12.3
4           1  H3_date  2026-11-30 00:00:00
5           1       H3                 22.3
6           1  H4_date  2106-10-30 00:00:00
7           1       H4                 42.3
10          1  H6_date  2006-10-30 00:00:00
11          1       H6                  2.3
12          1  H7_date                  NaN
13          1       H7                  2.3
14          1  H8_date  2006-10-30 00:00:00
15          1       H8                  NaN

然后,如果需要,您可以以此为起点进行调整。

【讨论】:

  • 我知道当其中一个元素为真时 any() 将返回真。我在这里将有效值(NA 以外的任何值)视为True。我是否正确理解,当我在您的代码中将 .any() 替换为 .all() 时,我不应该看到任何 NA。所以它也应该排除记录号 12,13,14,15 吗?但我看到了他们。我是不是搞错了?
【解决方案3】:

你可以使用:

col = [x for x in df.columns if "date" in x] for column in col: df.dropna(subset=[column,column[:-4]], how = 'all',inplace=True)

subset会选择检测到NA的行,how指定行上的条件(这里2行都必须是NA)inplace修改当前DataFrame

【讨论】:

  • 在这种情况下,您已经给出了列名。但我可能不知道列名。在这种情况下我该如何放弃?有超过 150 列,数据源源不断。所以我真的不知道列名
  • 你知道他们的索引吗?
  • @AVLES 按照命名约定执行列,例如:总是有 H 吗?和 H?_date 对?
  • 好吧,所以你想删除有任何一对 (HX;HXDate) 完全不适用的每一行?
  • 从列名中取出“日期”,假设日期在最后一个位置。如果不是我让你修改字符串以取出“日期”关键字并获取第二列名称
猜你喜欢
  • 2016-07-07
  • 2019-09-13
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 2016-11-11
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
相关资源
最近更新 更多