109

I have a DataFrame object similar to this one:

       onset    length
1      2.215    1.3
2     23.107    1.3
3     41.815    1.3
4     61.606    1.3
...

What I would like to do is insert a row at a position specified by some index value and update the following indices accordingly. E.g.:

       onset    length
1      2.215    1.3
2     23.107    1.3
3     30.000    1.3  # new row
4     41.815    1.3
5     61.606    1.3
...

What would be the best way to do this?

2
  • Possible to add row at particular index: df1 = pd.DataFrame(np.insert(df1.values, index+1, values=[" "] * len(df1.columns), axis=0),columns = df1.columns)
    – Anonymous
    Commented Feb 1, 2019 at 9:51
  • You could also take the transpose and find the respective columns instead.
    – user9205630
    Commented Mar 2, 2019 at 9:26

4 Answers 4

104

You could slice and use concat to get what you want.

from pandas import DataFrame, concat
line = DataFrame({"onset": 30.0, "length": 1.3}, index=[3])
df2 = concat([df.iloc[:2], line, df.iloc[2:]]).reset_index(drop=True)

This will produce the dataframe in your example output. As far as I'm aware, concat is the best method to achieve an insert type operation in pandas, but admittedly I'm by no means a pandas expert.

4
  • 1
    @bdiamante Hi, please have a look at this question here stackoverflow.com/questions/44599589/…
    – Liza
    Commented Jun 21, 2017 at 21:53
  • @bdiamante it is replacing the row at index 3 when trying to insert a new row a index 3. How can keep the existing row at index 3 and at a new row after that? Commented Apr 3, 2020 at 18:57
  • 1
    The one's coming across this answer, assuming they imported pandas as import pandas as pd, might will need to add pd. before DataFrame and concat, as pd.DataFrame, else one will get a NameError: name 'DataFrame' is not defined. Commented Oct 9, 2022 at 12:07
  • @ShashankShekher: If you don't want to lose the existing index labels, then don't call .reset_index(drop=True). This also prevents losing the oldest duplicate row.
    – mins
    Commented May 9 at 11:38
42

I think it's even easier without concat or append:

df.loc[2.5] = 30.0, 1.3
df = df.sort_index().reset_index(drop=True)

(Supposing that the index is as provided, starting from 1)

2
  • 1
    This works wonderfully, thanks. And it's simpler than the other suggested solutions.
    – KBurchfiel
    Commented May 26, 2023 at 15:35
  • Sneaky. I like it :-)
    – Tunneller
    Commented Oct 30, 2023 at 22:22
40

I find it more readable to sort rather than slice and concatenate.

line = DataFrame({"onset": 30.0, "length": 1.3}, index=[2.5])
df = df.append(line, ignore_index=False)
df = df.sort_index().reset_index(drop=True)
1
  • 1
    The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. Commented Oct 9, 2022 at 11:53
0

If you want to keep the original indexes this might work beter:

df = pd.DataFrame(dict(x=[0, 1, 2, 3, 4]))
df_update = pd.DataFrame(dict(x=[10, 11, 12]), index=[3, 4, 5])

# concat df_update first
df = pd.concat([df_update, df], axis=0)

# drop duplicates, updates will be prioritized
df = df.iloc[df.index.drop_duplicates()]

# sort to regain order
df.sort_index(inplace=True)

Not the answer you're looking for? Browse other questions tagged or ask your own question.