根据列值重复数据框的各个部分

时间:2019-06-22 14:22:24

标签: python pandas

我要收集许多天的数据,而不是每天都要填写,我可以选择说一天中的数据实际上应该是另一天的重复。我想将现有数据框中的某些行重复到指定为重复的日子。我有一列指示当前日期是从哪一天开始重复,但我陷入了错误。

我已经找到了基于列值重复行n次的方法,但是我试图使用列作为索引来重复前行的数据。

我想使用“重复”列作为索引,将第一天的“数据”列中的部分复制到第三天的“数据”列中。我想在更多不同的日子里这样做。

data = [['1', 5,np.NaN], ['1',5,np.NaN],['1',5,np.NaN], ['2', 6,np.NaN],['2', 6,np.NaN],['2', 6,np.NaN], ['3',np.NaN,1], ['3',np.NaN,np.NaN],['3', np.NaN,np.NaN]] 

df = pd.DataFrame(data, columns = ['Day', 'Data','repeat_tag']) 

2 个答案:

答案 0 :(得分:0)

设置

# Start with Valdi_Bo's expanded example data
data = [['1', 51, np.nan], ['1', 52, np.nan],     ['1', 53, np.nan],
        ['2', 61, np.nan], ['2', 62, np.nan],     ['2', 63, np.nan],
        ['3', np.nan, 1],  ['3', np.nan, np.nan], ['3', np.nan, np.nan],
        ['4', np.nan, 2],  ['4', np.nan, np.nan], ['4', np.nan, np.nan]]
df = pd.DataFrame(data, columns = ['Day', 'Data', 'repeat_tag'])

# Convert Day to integer data type
df['Day'] = df['Day'].astype(int)

# Spread repeat_tag values into all rows of tagged day
df['repeat_tag'] = df.groupby('Day')['repeat_tag'].ffill()

解决方案

# Within each day, assign a number to each row
df['obs'] = df.groupby('Day').cumcount()

# Self-join
filler = (pd.merge(df, df, 
                   left_on=['repeat_tag', 'obs'], 
                   right_on=['Day', 'obs'])
            .set_index(['Day_x', 'obs'])['Data_y'])

# Fill missing data
df = df.set_index(['Day', 'obs'])
df.loc[df['Data'].isnull(), 'Data'] = filler
df = df.reset_index()

结果

df
    Day  obs  Data  repeat_tag
0     1    0  51.0         NaN
1     1    1  52.0         NaN
2     1    2  53.0         NaN
3     2    0  61.0         NaN
4     2    1  62.0         NaN
5     2    2  63.0         NaN
6     3    0  51.0         1.0
7     3    1  52.0         1.0
8     3    2  53.0         1.0
9     4    0  61.0         2.0
10    4    1  62.0         2.0
11    4    2  63.0         2.0

答案 1 :(得分:0)

我稍微扩展了您的测试数据:

data = [['1', 51, np.nan], ['1', 52, np.nan],     ['1', 53, np.nan],
        ['2', 61, np.nan], ['2', 62, np.nan],     ['2', 63, np.nan],
        ['3', np.nan, 1],  ['3', np.nan, np.nan], ['3', np.nan, np.nan],
        ['4', np.nan, 2],  ['4', np.nan, np.nan], ['4', np.nan, np.nan]]
df = pd.DataFrame(data, columns = ['Day', 'Data', 'repeat_tag'])

详细信息:

  • 4 天有观察结果。
  • 每个观察值具有不同值(数据)。
  • 为避免“单日复制”,将复制第'3'天的值 第'1'天,以及第'2'天的第'4'天。

我假设 repeat_tag 的非空值只能放在一个 观察“目标”日。

我还添加了 obsNo 列以标识特定日期的观察值:

df['obsNo'] = df.groupby('Day').cumcount().add(1);

(稍后需要)。

实际处理的第一步是生成 replDays 表,其中 Day 列是目标日, repeat_tag 来源日:

replDays = df.query('repeat_tag.notnull()')[['Day', 'repeat_tag']]
replDays.repeat_tag = replDays.repeat_tag.astype(int).apply(str)

使用 repeat_tag 列进行一些类型操作。 由于此列包含 NaN 值,而非null值是 int ,因此此列为 强制为 float64 。因此,要获取 string 类型(与 Day 相比) 必须转换:

  • 首先是 int ,以删除小数部分。
  • 然后转到 str

结果是:

  Day repeat_tag
6   3          1
9   4          2

(用第1天的数据填充第3天的数据,用第2天的数据填充第4天的数据)。

下一步是生成 replData 表:

replData = pd.merge(replDays, df, left_on='repeat_tag', right_on='Day',
    suffixes=('_src', ''))[['Day_src', 'Day', 'Data', 'obsNo']]\
    .set_index(['Day_src', 'obsNo']).drop(columns='Day')

结果是:

               Data
Day_src obsNo      
3       1      51.0
        2      52.0
        3      53.0
4       1      61.0
        2      62.0
        3      63.0

如您所见:

  • 只有一列替换数据-数据(从第1天到第2天)。
  • MutliIndex既包含日期又包含观察号(两者均为 正确进行 update 所需)。

最后一部分包括以下步骤:

  • df 复制到 res (结果),将索引设置为 Day obsNo 更新必需)。
  • 使用来自 replData 的数据更新此表。
  • Day obsNo 从索引移回“常规”列。

代码是:

res = df.copy().set_index(['Day', 'obsNo'])
res.update(replData)
res.reset_index(inplace=True)

如果需要,还可以删除 obsNo 列。

以及有关 Peter 解决方案的评论: 如果源数据包含任意一天的不同值,则其代码将失败 与 InvalidIndexError 一起使用,可能是由于缺少 在特定日期内的个人观察。 这证实了我添加 obsNo 列的想法是有效的。