pandas 数据框中连接关系表的层次结构
hierarchy in joining relation tables in pandas dataframe
我想知道是否有任何方式可以利用类似于分层索引的功能,但在 pandas table 的数据中。我有兴趣将多个数据帧组合成一个数据帧,其中一些数据帧在另一个数据帧中有一个 ID 的多个条目。
一如既往,最好只显示结构。
这是一个简化的数据框 1:
>>> df1
id txt
0 0 first sent
1 1 another one
2 2 I think you
3 3 will like this
4 4 will work
虽然数据帧 2 可能有几个属性对应于数据帧 1 的每个条目(按索引 ID):
>>> df2
attr id
0 chem 0
1 dis 0
2 chem 1
3 chem 1
4 chem 2
5 dis 2
6 dis 3
7 dis 3
8 dis 4
9 chem 4
所以尝试这样做:
import pandas as pd
id = range(0,5)
texts = ['first sent', 'another one', 'I think you', 'will like this']
df = pd.DataFrame({'txt':texts, 'id':id})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
合并后仅提供:
>>> df.merge(df2, on='id')
id txt attr
0 0 first sent chem
1 0 first sent dis
2 1 another one chem
3 1 another one chem
4 2 I think you chem
5 2 I think you dis
6 3 will like this dis
7 3 will like this dis
8 4 will work dis
9 4 will work chem
现在您可以看到 'txt' 列是重复的 - 在这种情况下,IMO 是不必要的,如果 df2
中每个 id 的属性很多,可能会导致一些严重的内存问题。有可能(在这种情况下)复制的文本数据比将数据表示为两个单独的数据帧所需的数据大数千倍。
我考虑过尝试将 'txt' 列作为分层索引的索引(尽管我确信这完全是错误的设计考虑),但即使如此,仍然存在重复。
>>> df.merge(df2, on='id').set_index(['id', 'txt'])
attr
id txt
0 first sent chem
first sent dis
1 another one chem
another one chem
2 I think you chem
I think you dis
3 will like this dis
will like this dis
4 will work dis
will work chem
有没有办法将信息存储在单个数据框中?
这是一个使用 pandas
categories 的内存高效解决方案。对于结果中 'txt' 列中的每个值,成本现在只是一个整数,这比存储文本字符串要便宜得多。
import pandas as pd
ids = range(0,4)
texts = ['first sent', 'another one', 'I think you', 'will like this']
df = pd.DataFrame({'txt':texts, 'id':ids})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
# convert to category codes and store mapping
df['txt'] = df['txt'].astype('category')
df_txt_cats = dict(enumerate(df['txt'].cat.categories))
df['txt'] = df['txt'].cat.codes
# perform merge - memory efficinet since result only uses integers
df_merged = df.merge(df2, on='id')
# rename categories from integers to text strings from previously stored mapping
df_merged['txt'] = df_merged['txt'].astype('category')
df_merged['txt'].cat.categories = list(map(df_txt_cats.get, df_merged['txt'].cat.categories))
df_merged.dtypes
# id int32
# txt category
# attr object
# dtype: object
你的第二个选项是更有效的内存。原因是您最终会得到一个多索引,并且实际文本值不会在内存中重复。它们仅在输出表示中显示为重复项。如果您查看实际数据帧的 merge_2.index
的输出,您会发现没有重复。
演示:
# I've added some extra dummy text to show how this works with larger strings
extra_txt = ",".join([str(i) for i in range(5000)])
import pandas as pd
id = range(0,5)
texts = [
'first sent' + extra_txt,
'another one' + extra_txt,
'I think you' + extra_txt,
'will like this' + extra_txt,
'will work' + extra_txt,
]
df = pd.DataFrame({'txt':texts, 'id':id})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
merge_1 = df.merge(df2, on='id')
merge_2 = df.merge(df2, on='id').set_index(['id', 'txt'])
版本 1 内存使用:
In []: merge_1.memory_usage(index=True, deep=True).sum()
Out[]: 240335
版本 2 内存使用:
In []: merge_2.memory_usage(index=True, deep=True).sum()
Out[]: 120565
我想知道是否有任何方式可以利用类似于分层索引的功能,但在 pandas table 的数据中。我有兴趣将多个数据帧组合成一个数据帧,其中一些数据帧在另一个数据帧中有一个 ID 的多个条目。
一如既往,最好只显示结构。 这是一个简化的数据框 1:
>>> df1
id txt
0 0 first sent
1 1 another one
2 2 I think you
3 3 will like this
4 4 will work
虽然数据帧 2 可能有几个属性对应于数据帧 1 的每个条目(按索引 ID):
>>> df2
attr id
0 chem 0
1 dis 0
2 chem 1
3 chem 1
4 chem 2
5 dis 2
6 dis 3
7 dis 3
8 dis 4
9 chem 4
所以尝试这样做:
import pandas as pd
id = range(0,5)
texts = ['first sent', 'another one', 'I think you', 'will like this']
df = pd.DataFrame({'txt':texts, 'id':id})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
合并后仅提供:
>>> df.merge(df2, on='id')
id txt attr
0 0 first sent chem
1 0 first sent dis
2 1 another one chem
3 1 another one chem
4 2 I think you chem
5 2 I think you dis
6 3 will like this dis
7 3 will like this dis
8 4 will work dis
9 4 will work chem
现在您可以看到 'txt' 列是重复的 - 在这种情况下,IMO 是不必要的,如果 df2
中每个 id 的属性很多,可能会导致一些严重的内存问题。有可能(在这种情况下)复制的文本数据比将数据表示为两个单独的数据帧所需的数据大数千倍。
我考虑过尝试将 'txt' 列作为分层索引的索引(尽管我确信这完全是错误的设计考虑),但即使如此,仍然存在重复。
>>> df.merge(df2, on='id').set_index(['id', 'txt'])
attr
id txt
0 first sent chem
first sent dis
1 another one chem
another one chem
2 I think you chem
I think you dis
3 will like this dis
will like this dis
4 will work dis
will work chem
有没有办法将信息存储在单个数据框中?
这是一个使用 pandas
categories 的内存高效解决方案。对于结果中 'txt' 列中的每个值,成本现在只是一个整数,这比存储文本字符串要便宜得多。
import pandas as pd
ids = range(0,4)
texts = ['first sent', 'another one', 'I think you', 'will like this']
df = pd.DataFrame({'txt':texts, 'id':ids})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
# convert to category codes and store mapping
df['txt'] = df['txt'].astype('category')
df_txt_cats = dict(enumerate(df['txt'].cat.categories))
df['txt'] = df['txt'].cat.codes
# perform merge - memory efficinet since result only uses integers
df_merged = df.merge(df2, on='id')
# rename categories from integers to text strings from previously stored mapping
df_merged['txt'] = df_merged['txt'].astype('category')
df_merged['txt'].cat.categories = list(map(df_txt_cats.get, df_merged['txt'].cat.categories))
df_merged.dtypes
# id int32
# txt category
# attr object
# dtype: object
你的第二个选项是更有效的内存。原因是您最终会得到一个多索引,并且实际文本值不会在内存中重复。它们仅在输出表示中显示为重复项。如果您查看实际数据帧的 merge_2.index
的输出,您会发现没有重复。
演示:
# I've added some extra dummy text to show how this works with larger strings
extra_txt = ",".join([str(i) for i in range(5000)])
import pandas as pd
id = range(0,5)
texts = [
'first sent' + extra_txt,
'another one' + extra_txt,
'I think you' + extra_txt,
'will like this' + extra_txt,
'will work' + extra_txt,
]
df = pd.DataFrame({'txt':texts, 'id':id})
df2 = pd.DataFrame({'attr':['chem', 'dis', 'chem', 'chem', 'chem', 'dis', 'dis', 'dis', 'dis', 'chem'] ,'id':[0,0,1,1,2,2,3,3,4,4]})
merge_1 = df.merge(df2, on='id')
merge_2 = df.merge(df2, on='id').set_index(['id', 'txt'])
版本 1 内存使用:
In []: merge_1.memory_usage(index=True, deep=True).sum()
Out[]: 240335
版本 2 内存使用:
In []: merge_2.memory_usage(index=True, deep=True).sum()
Out[]: 120565