web-dev-qa-db-fra.com

Insertion de nouvelles lignes dans la trame de données de pandas à des index spécifiques

J'ai un bloc de données suivant df avec deux colonnes "identifiant", "valeurs" et "subid":

     identifier   values    subid
0      1          101       1
1      1          102       1
2      1          103       2 #index in list x        
3      1          104       2
4      1          105       2
5      2          106       3   
6      2          107       3
7      2          108       3
8      2          109       4 #index in list x
9      2          110       4
10     3          111       5
11     3          112       5 
12     3          113       6 #index in list x

J'ai une liste d'indices, disons 

x = [2, 8, 12] 

Je veux insérer des lignes juste avant les indices mentionnés dans la liste x. Comme pour la ligne insérée juste avant l’index 2, les valeurs suivantes seront attribuées: même identificateur que la ligne de l’index 2, c’est-à-dire 1; mêmes valeurs que la ligne d'index 2, c'est-à-dire 103; mais le subid dans la nouvelle ligne serait ((subid à l'index 2) - 1), ou simplement le subid de la ligne précédente, c'est-à-dire 1.

Vous trouverez ci-dessous le résultat final attendu:

   identifier   values    subid
0      1          101       1
1      1          102       1
2      1          103       1 #new row inserted     
3      1          103       2 #index in list x        
4      1          104       2
5      1          105       2
6      2          106       3   
7      2          107       3
8      2          108       3
9      2          109       3 #new row inserted
10     2          109       4 #index in list x
11     2          110       4
12     3          111       5
13     3          112       5 
14     3          113       5 #new row inserted
15     3          113       6 #index in list x

Le code que j'ai essayé:

 m = df.index       #storing the indices of the df
 #m

 for i in m:
     if i in x:     #x is the given list of indices
         df.iloc[i-1]["identifier"] = df.iloc[i]["identifier"]
         df.iloc[i-1]["values"] = df.iloc[i]["values"]
         df.iloc[i-1]["subid"] = (df.iloc[i]["subid"]-1)
 df

Le code ci-dessus est simplement remplacer les lignes à (i-1) indices et ne pas insérer les lignes supplémentaires avec les valeurs ci-dessus. S'il vous plaît aider.

S'il vous plaît laissez-moi savoir si quelque chose n'est pas clair.

8
Liza

Préserver l'ordre des index est la partie la plus délicate. Je ne suis pas sûr que ce soit le moyen le plus efficace de le faire, mais cela devrait fonctionner.

x = [2,8,12]
rows = []
cur = {}

for i in df.index:
    if i in x:
        cur['index'] = i
        cur['identifier'] = df.iloc[i].identifier
        cur['values'] = df.iloc[i]['values']
        cur['subid'] = df.iloc[i].subid - 1
        rows.append(cur)
        cur = {}

Ensuite, parcourez la nouvelle liste de lignes et effectuez un concaténage incrémentiel en insérant chaque nouvelle ligne à l'emplacement approprié. 

offset = 0; #tracks the number of rows already inserted to ensure rows are inserted in the correct position

for d in rows:
    df = pd.concat([df.head(d['index'] + offset), pd.DataFrame([d]), df.tail(len(df) - (d['index']+offset))])
    offset+=1


df.reset_index(inplace=True)
df.drop('index', axis=1, inplace=True)
df

    level_0 identifier  subid   values
0         0          1      1      101
1         1          1      1      102
2         0          1      1      103
3         2          1      2      103
4         3          1      2      104
5         4          1      2      105
6         5          2      3      106
7         6          2      3      107
8         7          2      3      108
9         0          2      3      109
10        8          2      4      109
11        9          2      4      110
12       10          3      5      111
13       11          3      5      112
14        0          3      5      113
15       12          3      6      113
4
bdiamante

soustraire où la ligne précédente est différente de la ligne actuelle

# edit in place
df['values'] -= df.identifier.ne(df.identifier.shift().bfill())
df

    identifier  values
0            1     101
1            1     102
2            1     103
3            1     104
4            1     105
5            2     105
6            2     107
7            2     108
8            2     109
9            2     110
10           3     110
11           3     112
12           3     113

Ou

# new dataframe
df.assign(values=df['values'] - df.identifier.ne(df.identifier.shift().bfill()))

    identifier  values
0            1     101
1            1     102
2            1     103
3            1     104
4            1     105
5            2     105
6            2     107
7            2     108
8            2     109
9            2     110
10           3     110
11           3     112
12           3     113
2
piRSquared