如何处理pandas数据框中的缺失数据?

3
我有一个 Pandas 数据帧,其中包含以下信息:
  • 每个时间戳有一定数量的托盘(1-4之间),共有8个托盘可供选择。(所以每个时间戳最多有4个托盘。)
  • 每个托盘包含4个位置。
数据帧可能如下所示:
df = 

     timestamp    t_idx  position  error    type    SNR
 0   16229767       5        2       1       T1     123
 1   16229767       5        1       0       T1     123
 3   16229767       5        3       0       T1     123
 4   16229767       5        4       0       T1     123
 5   16229767       3        3       1       T9      38
 6   16229767       3        1       0       T9      38
 7   16229767       3        4       0       T9      38
 8   29767162       7        1       0       T4     991
 9   29767162       7        4       1       T4     991 

如果我们看时间戳"16229767",有两个托盘正在使用:托盘3和托盘5。 托盘5的每个位置都被检测到了。 然而,由于位置2缺失数据,托盘3的数据是不完整的。
我想通过编程方式来修复并添加这一行。
 10  16229767       3        2       1       T9      38

 11  29767162       7        2       1       T4     991 
 12  29767162       7        3       1       T4     991 

我不确定如何正确处理缺失的值。我目前采用的是比较幼稚的方法:

timestamps = df['timestamp'].unique()
for ts in timestamps:
    tray_ids = df.loc[df['timestamp'] == timestamps ]["Tray ID"].unique()
    for t_id in tray_ids:
        # For timestamp and tray id: Each position (1 to 4) should exist once!
        # df.loc[(df['timestamp'] == ts) & (df['Tray ID'] == t_id)] 
        # if not, append the position on the tray and set error to 1

我应该如何查找并添加丢失的行到数据框中?

===

编辑: 我在简化我的示例时遗漏了一些相关信息: 还存在其他列,新生成的行应每个托盘拥有相同的内容。通过添加两列使其更加清晰。

此外,有一个关于错误的问题:对于每一个要添加的行,错误应该自动为1(无逻辑可言)。


1
你可以尝试将数据从长格式转换为宽格式,然后再转回来。如果你明白我的意思,在宽格式中,隐式缺失值会变得明显起来。 - TMBailey
1
error 值是如何设置的? - Corralien
请提供预期的输出数据框。 - sammywemmy
@Corralien,每添加一行新代码,错误应该始终为1。 - Drimer
1
@sammywemmy,我应该怎么帮忙呢?在我的初始问题中,我提到了一个期望的结果。 - Drimer
4个回答

1
我们可以先将position转换为分类类型,使用groupby填充所有缺失值,并将相应的error值设置为1
我们还必须填写typeSNR列的正确值,如下所示:
>>> df['position'] = pd.Categorical(df['position'], categories=df['position'].unique())
>>> df_grouped = df.groupby(['timestamp', 't_idx', 'position'], as_index=False).first()
>>> df_grouped['error'] = df_grouped['error'].fillna(1)

>>> df_grouped.sort_values('type', inplace=True)
>>> df_grouped['type'] = df_grouped.groupby(['timestamp','t_idx'])['type'].ffill().bfill()

>>> df_grouped.sort_values('SNR', inplace=True)
>>> df_grouped['SNR'] = df_grouped.groupby(['timestamp','t_idx'])['SNR'].ffill().bfill()

>>> df_grouped = df_grouped.reset_index(drop=True)
    timestamp   t_idx   position    error   type    SNR
0   16229767    3       1           0.0     T9      38.0
1   16229767    3       3           1.0     T9      38.0
2   16229767    3       4           0.0     T9      38.0
3   16229767    5       2           1.0     T1      123.0
4   16229767    5       1           0.0     T1      123.0
5   16229767    5       3           0.0     T1      123.0
6   16229767    5       4           0.0     T1      123.0
7   29767162    7       1           0.0     T4      991.0
8   29767162    7       4           1.0     T4      991.0
9   16229767    3       2           1.0     T9      38.0
10  16229767    7       2           1.0     T4      991.0
11  16229767    7       1           1.0     T4      991.0
12  16229767    7       3           1.0     T4      991.0
13  16229767    7       4           1.0     T4      991.0
14  29767162    3       2           1.0     T4      991.0
15  29767162    3       1           1.0     T4      991.0
16  29767162    3       3           1.0     T4      991.0
17  29767162    3       4           1.0     T4      991.0
18  29767162    5       2           1.0     T4      991.0
19  29767162    5       1           1.0     T4      991.0
20  29767162    5       3           1.0     T4      991.0
21  29767162    5       4           1.0     T4      991.0
22  29767162    7       2           1.0     T4      991.0
23  29767162    7       3           1.0     T4      991.0

然后,我们根据原始 DataFrame 中的值进行过滤,以获得预期结果:

>>> df_grouped[
...     pd.Series(
...         list(zip(df_grouped['timestamp'].values, df_grouped['t_idx'].values))
...     ).isin(list(zip(df['timestamp'].values, df['t_idx'].values)))
... ].sort_values(by=['timestamp', 't_idx']).reset_index(drop=True)
    timestamp   t_idx   position    error   type    SNR
0   16229767    3       1           0.0     T9      38.0
1   16229767    3       3           1.0     T9      38.0
2   16229767    3       4           0.0     T9      38.0
3   16229767    3       2           1.0     T9      38.0
4   16229767    5       2           1.0     T1      123.0
5   16229767    5       1           0.0     T1      123.0
6   16229767    5       3           0.0     T1      123.0
7   16229767    5       4           0.0     T1      123.0
8   29767162    7       1           0.0     T4      991.0
9   29767162    7       4           1.0     T4      991.0
10  29767162    7       2           1.0     T4      991.0
11  29767162    7       3           1.0     T4      991.0

谢谢您的回答!我喜欢这个解决方案,但是在我的初始问题中错过了一些信息,我想知道这个解决方案是否容易修复? - Drimer
我看到你在问题中更改了初始数据,因此我重新制定了答案以确保一切正确。希望能有所帮助 ;) ! - tlentali

1

pyjanitor有一个complete函数,可以显式地暴露缺失的值(pyjanitor是一组方便的Pandas函数);

在上述挑战中,只需要暴露数据中显式缺失的值:

# pip install pyjanitor
import pandas as pd
import janitor
(df.complete(['timestamp', 't_idx', 'type', 'SNR'], 'position')
   .fillna({"error":1}, downcast='infer')
   .filter(df.columns)
)
 
    timestamp  t_idx  position  error type  SNR
0    16229767      5         2      1   T1  123
1    16229767      5         1      0   T1  123
2    16229767      5         3      0   T1  123
3    16229767      5         4      0   T1  123
4    16229767      3         2      1   T9   38
5    16229767      3         1      0   T9   38
6    16229767      3         3      1   T9   38
7    16229767      3         4      0   T9   38
8    29767162      7         2      1   T4  991
9    29767162      7         1      0   T4  991
10   29767162      7         3      1   T4  991
11   29767162      7         4      1   T4  991

在上面的代码中,仅需要['timestamp', 't_idx', 'type', 'SNR']position的组合来生成缺失值,将输出限制在DataFrame中明确的缺失值内部;如果需要所有缺失值的组合,则括号将被删除,您可能会得到一个更大的DataFrame。

0

您可以使用固定位置的时间戳创建一个新的数据框。然后将它们合并在一起,您将得到给定缺失位置的错误列上的NaN值。然后您可以将NaN填充为1。

示例代码:

unique_id = df.timestamp.unique().tolist()
df_tmp = pd.DataFrame({'timestamp':unique_id,'position':range(4)})
df = pd.merge(df_tmp, df, on=["timestamp", "position"], how="left")
df.error.fillna(1)

第二行出现了一个错误:"ValueError: arrays must all be same length"。还要注意问题略有改变。 - Drimer

0

你可以尝试这段代码:

def foo(df):
    set_ = set(range(1,5))
    if df.position.unique().size < 4:
        diff_ = set_.difference(df.position.unique())
        add_df = df.iloc[:len(diff_),:].copy()
        add_df.loc[:, 'position'] = list(diff_)
        # I did not understand by what rule the values in the error column are set. You can install it as you need
        result_df = pd.concat([df, add_df], ignore_index=True)
        return result_df
    else: 
        return df

group = df.groupby(['timestamp', 't_idx'])
group.apply(foo)


    timestamp   t_idx   position    error
0   16229767     3        3           1
1   16229767     3        1           0
2   16229767     3        4           0
3   16229767     3        2           1
4   16229767     5        2           1
5   16229767     5        1           0
6   16229767     5        3           0
7   16229767     5        4           0
8   29767162     7        1           0
9   29767162     7        4           1
10  29767162     7        2           0
11  29767162     7        3           1

似乎“if”从未被执行,因为我的数据集包含所有可能的位置。 - Drimer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接