Je comprends que pandas est conçu pour charger DataFrame
complètement peuplé, mais il me faut créer un DataFrame vide puis ajouter des lignes, une par une. Quelle est la meilleure façon de procéder ?
J'ai créé avec succès un DataFrame vide avec:
res = DataFrame(columns=('lib', 'qty1', 'qty2'))
Ensuite, je peux ajouter une nouvelle ligne et remplir un champ avec:
res = res.set_value(len(res), 'qty1', 10.0)
Cela fonctionne mais semble très étrange: -/(il échoue pour ajouter une valeur de chaîne)
Comment puis-je ajouter une nouvelle ligne à mon DataFrame (avec un type de colonne différent)?
>>> import pandas as pd
>>> from numpy.random import randint
>>> df = pd.DataFrame(columns=['lib', 'qty1', 'qty2'])
>>> for i in range(5):
>>> df.loc[i] = ['name' + str(i)] + list(randint(10, size=2))
>>> df
lib qty1 qty2
0 name0 3 3
1 name1 2 4
2 name2 2 8
3 name3 2 1
4 name4 9 6
Si vous pouvez obtenir toutes les données pour le bloc de données au début, il existe une approche beaucoup plus rapide que l'ajout d'un bloc de données:
J'avais une tâche similaire pour laquelle l'ajout à un cadre de données ligne par ligne prenait 30 minutes et la création d'un cadre de données à partir d'une liste de dictionnaires terminée en quelques secondes.
rows_list = []
for row in input_rows:
dict1 = {}
# get input row in dictionary format
# key = col_name
dict1.update(blah..)
rows_list.append(dict1)
df = pd.DataFrame(rows_list)
Vous pouvez utiliser pandas.concat()
ou DataFrame.append()
. Pour plus de détails et des exemples, voir Fusionner, joindre et concaténer .
Si vous connaissez le nombre d'entrées ex ante, vous devez préallouer l'espace en fournissant également l'index (en prenant l'exemple de données d'une réponse différente):
import pandas as pd
import numpy as np
# we know we're gonna have 5 rows of data
numberOfRows = 5
# create dataframe
df = pd.DataFrame(index=np.arange(0, numberOfRows), columns=('lib', 'qty1', 'qty2') )
# now fill it up row by row
for x in np.arange(0, numberOfRows):
#loc or iloc both work here since the index is natural numbers
df.loc[x] = [np.random.randint(-1,1) for n in range(3)]
In[23]: df
Out[23]:
lib qty1 qty2
0 -1 -1 -1
1 0 0 0
2 -1 0 -1
3 0 -1 0
4 -1 0 0
Comparaison de vitesse
In[30]: %timeit tryThis() # function wrapper for this answer
In[31]: %timeit tryOther() # function wrapper without index (see, for example, @fred)
1000 loops, best of 3: 1.23 ms per loop
100 loops, best of 3: 2.31 ms per loop
Et - à partir des commentaires - avec une taille de 6000, la différence de vitesse devient encore plus grande:
L'augmentation de la taille du tableau (12) et du nombre de lignes (500) rend la différence de vitesse plus frappante: 313 ms contre 2,29 s
Ça fait longtemps, mais j'ai aussi fait face au même problème. Et trouvé ici beaucoup de réponses intéressantes. Donc, j'ai été confondu quelle méthode à utiliser.
Dans le cas de l'ajout de nombreuses lignes à la structure de données, je m'intéressais aux performances de vitesse . J'ai donc essayé 4 méthodes les plus populaires et vérifié leur vitesse.
MIS À JOUR EN 2019 à l'aide de nouvelles versions de packages. Également mis à jour après @ commentaire de FooBar
Résultats (en secondes):
|------------|-------------|-------------|-------------|
| Approach | 1000 rows | 5000 rows | 10 000 rows |
|------------|-------------|-------------|-------------|
| .append | 0.69 | 3.39 | 6.78 |
|------------|-------------|-------------|-------------|
| .loc w/o | 0.74 | 3.90 | 8.35 |
| prealloc | | | |
|------------|-------------|-------------|-------------|
| .loc with | 0.24 | 2.58 | 8.70 |
| prealloc | | | |
|------------|-------------|-------------|-------------|
| dict | 0.012 | 0.046 | 0.084 |
|------------|-------------|-------------|-------------|
Merci également à @ krassowski pour un commentaire utile - J'ai mis à jour le code.
Donc, j'utilise l'addition par le dictionnaire pour moi-même.
Code:
import pandas as pd
import numpy as np
import time
del df1, df2, df3, df4
numOfRows = 1000
# append
startTime = time.perf_counter()
df1 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows-4):
df1 = df1.append( dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']), ignore_index=True)
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)
# .loc w/o prealloc
startTime = time.perf_counter()
df2 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows):
df2.loc[i] = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)
# .loc with prealloc
df3 = pd.DataFrame(index=np.arange(0, numOfRows), columns=['A', 'B', 'C', 'D', 'E'] )
startTime = time.perf_counter()
for i in range( 1,numOfRows):
df3.loc[i] = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df3.shape)
# dict
startTime = time.perf_counter()
row_list = []
for i in range (0,5):
row_list.append(dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']))
for i in range( 1,numOfRows-4):
dict1 = dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E'])
row_list.append(dict1)
df4 = pd.DataFrame(row_list, columns=['A','B','C','D','E'])
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df4.shape)
P.S. Je crois que ma réalisation n’est pas parfaite et qu’il ya peut-être une optimisation.
mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
df.loc[len(df)] = row
Pour des ajouts efficaces, voir Comment ajouter une ligne supplémentaire à un pandas dataframe et Définition avec agrandissement .
Ajoutez des lignes via loc/ix
sur des données d'index de clé non existantes . par exemple. :
In [1]: se = pd.Series([1,2,3])
In [2]: se
Out[2]:
0 1
1 2
2 3
dtype: int64
In [3]: se[5] = 5.
In [4]: se
Out[4]:
0 1.0
1 2.0
2 3.0
5 5.0
dtype: float64
Ou:
In [1]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
.....: columns=['A','B'])
.....:
In [2]: dfi
Out[2]:
A B
0 0 1
1 2 3
2 4 5
In [3]: dfi.loc[:,'C'] = dfi.loc[:,'A']
In [4]: dfi
Out[4]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
In [5]: dfi.loc[3] = 5
In [6]: dfi
Out[6]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
3 5 5 5
Vous pouvez ajouter une seule ligne sous forme de dictionnaire à l'aide de l'option ignore_index
.
>>> f = pandas.DataFrame(data = {'Animal':['cow','horse'], 'Color':['blue', 'red']})
>>> f
Animal Color
0 cow blue
1 horse red
>>> f.append({'Animal':'mouse', 'Color':'black'}, ignore_index=True)
Animal Color
0 cow blue
1 horse red
2 mouse black
Par souci de la façon pythonique, ajoutez ici ma réponse:
res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
res = res.append([{'qty1':10.0}], ignore_index=True)
print(res.head())
lib qty1 qty2
0 NaN 10.0 NaN
Vous pouvez également créer une liste de listes et la convertir en une base de données -
import pandas as pd
columns = ['i','double','square']
rows = []
for i in range(6):
row = [i, i*2, i*i]
rows.append(row)
df = pd.DataFrame(rows, columns=columns)
donnant
i double carré 0 0 0 0 1 1 2 1 2 2 4 4 3 3 6 9 4 4 8 16 5 5 10 25
Ce n’est pas une réponse à la question OP mais un exemple de jouet pour illustrer la réponse de @ShikharDua au-dessus de laquelle j’ai trouvé très utile.
Bien que ce fragment soit trivial, dans les données réelles, j'avais 1 000 rangées et de nombreuses colonnes et je souhaitais pouvoir regrouper différentes colonnes, puis effectuer les statistiques ci-dessous pour plus d'une colonne de taget. Il était donc très pratique d’avoir une méthode fiable pour construire le bloc de données ligne par ligne. Merci @ShikharDua!
import pandas as pd
BaseData = pd.DataFrame({ 'Customer' : ['Acme','Mega','Acme','Acme','Mega','Acme'],
'Territory' : ['West','East','South','West','East','South'],
'Product' : ['Econ','Luxe','Econ','Std','Std','Econ']})
BaseData
columns = ['Customer','Num Unique Products', 'List Unique Products']
rows_list=[]
for name, group in BaseData.groupby('Customer'):
RecordtoAdd={} #initialise an empty dict
RecordtoAdd.update({'Customer' : name}) #
RecordtoAdd.update({'Num Unique Products' : len(pd.unique(group['Product']))})
RecordtoAdd.update({'List Unique Products' : pd.unique(group['Product'])})
rows_list.append(RecordtoAdd)
AnalysedData = pd.DataFrame(rows_list)
print('Base Data : \n',BaseData,'\n\n Analysed Data : \n',AnalysedData)
Compris de manière simple et agréable:
>>> df
A B C
one 1 2 3
>>> df.loc["two"] = [4,5,6]
>>> df
A B C
one 1 2 3
two 4 5 6
Voici le moyen d'ajouter/ajouter une ligne dans pandas DataFrame
def add_row(df, row):
df.loc[-1] = row
df.index = df.index + 1
return df.sort_index()
add_row(df, [1,2,3])
Il peut être utilisé pour insérer/ajouter une ligne dans un champ vide ou peuplé pandas DataFrame
Créez un nouvel enregistrement (trame de données) et ajoutez-le à old_data_frame.
liste de contrôle de valeurs et des colonnes noms correspondants pour créer un new_record (data_frame)
new_record = pd.DataFrame([[0,'abcd',0,1,123]],columns=['a','b','c','d','e'])
old_data_frame = pd.concat([old_data_frame,new_record])
Une autre façon de le faire (probablement pas très performant):
# add a row
def add_row(df, row):
colnames = list(df.columns)
ncol = len(colnames)
assert ncol == len(row), "Length of row must be the same as width of DataFrame: %s" % row
return df.append(pd.DataFrame([row], columns=colnames))
Vous pouvez également améliorer la classe DataFrame comme ceci:
import pandas as pd
def add_row(self, row):
self.loc[len(self.index)] = row
pd.DataFrame.add_row = add_row
Faites simple. En prenant la liste comme entrée qui sera ajoutée comme ligne dans le cadre de données: -
import pandas as pd
res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
for i in range(5):
res_list = list(map(int, input().split()))
res = res.append(pd.Series(res_list,index=['lib','qty1','qty2']), ignore_index=True)
import pandas as pd
t1=pd.DataFrame()
for i in range(len(the number of rows)):
#add rows as columns
t1[i]=list(rows)
t1=t1.transpose()
t1.columns=list(columns)
Nous voyons souvent la construction df.loc[subscript] = …
à attribuer à une ligne DataFrame. Mikhail_Sam posted benchmarks contenant, entre autres, cette construction ainsi que la méthode utilisant dict et crée DataFrame à la fin . Il a trouvé que ce dernier était de loin le plus rapide. Mais si nous remplaçons le df3.loc[i] = …
(avec DataFrame préalloué) dans son code avec df3.values[i] = …
, le résultat change de manière significative, en ce sens que cette méthode est similaire à celle utilisant dict. Nous devrions donc prendre plus souvent en considération l'utilisation de df.values[subscript] = …
. Cependant, notez que .values
prend un indice de base zéro, qui peut être différent de DataFrame.index.