Je voudrais prendre un ensemble de données avec un tas de différents individus uniques, chacun avec plusieurs entrées, et attribuer à chaque individu un identifiant unique pour toutes leurs entrées. Voici un exemple de df:
FirstName LastName id
0 Tom Jones 1
1 Tom Jones 1
2 David Smith 1
3 Alex Thompson 1
4 Alex Thompson 1
Donc, fondamentalement, je veux que toutes les entrées pour Tom Jones aient id = 1, toutes les entrées pour David Smith pour avoir id = 2, toutes les entrées pour Alex Thompson pour avoir id = 3, et ainsi de suite.
J'ai donc déjà une solution, qui est une simple boucle python boucle itérant deux valeurs (une pour id, une pour index) et attribuant à l'individu un id en fonction de leur correspondance avec l'individu précédent:
x = 1
i = 1
while i < len(df_test):
if (df_test.LastName[i] == df_test.LastName[i-1]) &
(df_test.FirstName[i] == df_test.FirstName[i-1]):
df_test.loc[i, 'id'] = x
i = i+1
else:
x = x+1
df_test.loc[i, 'id'] = x
i = i+1
Le problème que je rencontre est que la trame de données a environ 9 millions d'entrées, donc avec cette boucle, cela aurait pris énormément de temps à s'exécuter. Quelqu'un peut-il penser à un moyen plus efficace de le faire? J'ai regardé groupby et multiindexing comme des solutions potentielles, mais je n'ai pas encore trouvé la bonne solution. Merci!
Vous pouvez joindre le nom et le prénom, les convertir en catégorie, puis obtenir les codes.
Bien sûr, plusieurs personnes portant le même nom auraient le même id
.
df = df.assign(id=(df['LastName'] + '_' + df['FirstName']).astype('category').cat.codes)
>>> df
FirstName LastName id
0 Tom Jones 0
1 Tom Jones 0
2 David Smith 1
3 Alex Thompson 2
4 Alex Thompson 2
Cette approche utilise .groupby()
et .ngroup()
(nouveau dans Pandas 0.20.2) pour créer la colonne id
:
df['id'] = df.groupby(['LastName','FirstName']).ngroup()
>>> df
First Second id
0 Tom Jones 0
1 Tom Jones 0
2 David Smith 1
3 Alex Thompson 2
4 Alex Thompson 2
J'ai vérifié les horaires et, pour le petit ensemble de données dans cet exemple, la réponse d'Alexandre est plus rapide:
%timeit df.assign(id=(df['LastName'] + '_' + df['FirstName']).astype('category').cat.codes)
1000 loops, best of 3: 848 µs per loop
%timeit df.assign(id=df.groupby(['LastName','FirstName']).ngroup())
1000 loops, best of 3: 1.22 ms per loop
Cependant, pour les cadres de données plus volumineux, l'approche groupby()
semble être plus rapide. Pour créer un grand ensemble de données représentatif, j'ai utilisé faker
pour créer une trame de données de 5000 noms, puis j'ai concaténé les 2000 premiers noms à cette trame de données pour créer une trame de données avec 7000 noms, dont 2000 étaient des doublons.
import faker
fakenames = faker.Faker()
first = [ fakenames.first_name() for _ in range(5000) ]
last = [ fakenames.last_name() for _ in range(5000) ]
df2 = pd.DataFrame({'FirstName':first, 'LastName':last})
df2 = pd.concat([df2, df2.iloc[:2000]])
L'exécution du timing sur cet ensemble de données plus volumineux donne:
%timeit df2.assign(id=(df2['LastName'] + '_' + df2['FirstName']).astype('category').cat.codes)
100 loops, best of 3: 5.22 ms per loop
%timeit df2.assign(id=df2.groupby(['LastName','FirstName']).ngroup())
100 loops, best of 3: 3.1 ms per loop
Vous souhaiterez peut-être tester les deux approches sur votre ensemble de données pour déterminer celle qui fonctionne le mieux compte tenu de la taille de vos données.
Cette méthode permet de définir le nom de la colonne 'id' avec une variable. De plus, je le trouve un peu plus facile à lire que les méthodes d'assignation ou de groupby.
# Create Dataframe
df = pd.DataFrame(
{'FirstName': ['Tom','Tom','David','Alex','Alex'],
'LastName': ['Jones','Jones','Smith','Thompson','Thompson'],
})
newIdName = 'id' # Set new name here.
df[newIdName] = (df['LastName'] + '_' + df['FirstName']).astype('category').cat.codes
Sortie:
>>> df
FirstName LastName id
0 Tom Jones 0
1 Tom Jones 0
2 David Smith 1
3 Alex Thompson 2
4 Alex Thompson 2