问:[Pandas]如何根据非常大的df中的名称有效地为具有多个条目的个人分配唯一ID

Sim*_*arp 18 python indexing dataframe pandas

我想采用一组不同的独特个体的数据集,每个人都有多个条目,并为每个人分配一个唯一的ID来表示他们所有的条目.这是df的一个例子:

      FirstName LastName  id
0     Tom       Jones     1
1     Tom       Jones     1
2     David     Smith     1
3     Alex      Thompson  1
4     Alex      Thompson  1
Run Code Online (Sandbox Code Playgroud)

所以,基本上我希望Tom Jones的所有条目都有id = 1,David Smith的所有条目都有id = 2,Alex Thompson的所有条目都有id = 3,依此类推.

所以我已经有了一个解决方案,这是一个死的简单python循环迭代两个值(一个用于id,一个用于索引),并根据它们是否与前一个人匹配来为个人分配一个id:

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
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是数据框有大约900万个条目,因此使用该循环会花费大量的时间来运行.谁能想到更有效的方法呢?我一直在寻找groupby和multiindexing作为潜在的解决方案,但尚未找到合适的解决方案.谢谢!

Cra*_*aig 26

此方法使用.groupby().ngroup()(Pandas 0.20.2中的新增内容)来创建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
Run Code Online (Sandbox Code Playgroud)

我检查了时间,对于这个例子中的小数据集,Alexander的答案更快:

%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
Run Code Online (Sandbox Code Playgroud)

但是,对于较大的数据帧,该groupby()方法似乎更快.为了创建一个大的,有代表性的数据集,我曾经faker创建了5000个名称的数据帧,然后将前2000个名称连接到这个数据帧,以生成一个包含7000个名称的数据帧,其中2000个是重复的.

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]])
Run Code Online (Sandbox Code Playgroud)

在这个更大的数据集上运行时间给出:

%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
Run Code Online (Sandbox Code Playgroud)

您可能希望在数据集上测试这两种方法,以确定哪种方法在给定数据大小的情况下效果最佳.

  • 对于较大的df`np.random.seed(123)N = 1000000 df = pd.DataFrame({'FirstName':np.random.randint(2000,size = N),'LastName':np.random.randint(2000 ,size = N)})df ['FirstName'] ='a'+ df ['FirstName']。astype(str)df ['LastName'] ='a'+ df ['LastName']。astype(str )df = df.sort_values([['FirstName','LastName']))-确实非常快;)祝您好运! (2认同)

Ale*_*der 17

您可以加入姓氏和名字,将其转换为类别,然后获取代码.

当然,具有相同名称的多个人将具有相同的名称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
Run Code Online (Sandbox Code Playgroud)