绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Pandas中兼并数组和字典功能的Series
2019-12-12 11:07:38

In [2]:

# 这段代码用于并排显示多个Series对象

fromitertoolsimportizip_longest

def C(*args, **kw):

gap = kw.pop("gap", 5)

results = []

    

for item in args:

if isinstance(item, tuple):

results.append("\n".join(unicode(row) for row in item).split("\n"))

            

for i, item in enumerate(results):

width = max(len(row.encode("gb2312")) for row in item)

results[i].insert(1, "-"*width)

results[i] = [row.encode("gb2312").ljust(width+gap).decode("gb2312") for row in item]

for row in izip_longest(*results, fillvalue=""):

print "".join(row)

兼并数组和字典功能的Series

In [3]:

importpandasaspd

Series对象本质上是一个NumPy的数组,因此NumPy的数组处理函数可以直接对Series进行处理。但是Series除了可以使用位置作为下标存取元素之外,还可以使用标签下标存取元素,这一点和字典相似。每个Series对象实际上都由两个数组组成:

index: 它是从NumPy数组继承的Index对象,保存标签信息。

values: 保存值的NumPy数组。

下面创建一个Series对象,并查看其两个属性:

In [4]:

s=pd.Series([1,2,3,4,5],index=["a","b","c","d","e"])

print s.index

print s.values

Index([a, b, c, d, e], dtype=object)

[1 2 3 4 5]

Series的下标存取,同时支持位置和标签两种形式:

In [5]:

prints[2],s["d"]

3 4

Series也支持位置切片和标签切片。位置切片遵循Python的切片规则,包括起始位置,但不包括结束位置;但标签切片则同时包括起始标签和结束标签。之所以如此设计是因为在使用标签切片时,通常我们不知道标签的顺序,如果不包含结束标签,很难确定结束标签的前一个标签是什么。

In [6]:

C((u"s[1:3]",s[1:3]),(u"s['b':'d']",s['b':'d']))

s[1:3]     s['b':'d']    

------     ----------    

b    2     b    2        

c    3     c    3        

d    4        

和NumPy数组一样,Series也可以使用一个位置列表或者位置数组进行存取;同时还可以使用标签列表和标签数组。

In [7]:

C((u"s[[1,3,2]]",s[[1,3,2]]),(u"s[['b','d','c']]",s[['b','d','c']]))

s[[1,3,2]]     s[['b','d','c']]    

----------     ----------------    

b    2         b    2            

d    4         d    4            

c    3         c    3            

可以看出Series同时具有数组和字典的功能,因此它也支持一些字典的方法,例如Series.iteritems():

In [8]:

printlist(s.iteritems())

[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]

Series魔法都在Index里

Index对象也是ndarray的派生类,values属性可以获得ndarray数组:

In [31]:

index=s.index

print index.__class__.mro()

index.values

[,,]

Out[31]:

array(['a', 'b', 'c', 'd', 'e'], dtype=object)

Index可以当作一维数组,支持所有的数组下标操作:

In [35]:

printindex[[1,3]]

print index[index > 'c']

print index[1::2]

Index([b, d], dtype=object)

Index([d, e], dtype=object)

Index([b, d], dtype=object)

Index也具有字典的映射功能,它将数组中的值映射到其位置:

Index.get_loc(value): 获得单个值value的下标

Index.get_indexer(values): 获得一组值values的下标,当值不存在时,得到-1

In [43]:

printindex.get_loc('c')

index.get_indexer(['a', 'c', 'z'])

2

Out[43]:

array([ 0, 2, -1])

Index的魔法在Engine里

Index对象的字典功能由其中的Engine对象提供:

In [18]:

e=s.index._engine

print e

In [22]:

e.get_loc('b')

Out[22]:

1

In [42]:

e.get_indexer(np.array(['a','d','e','z'],'O'))

Out[42]:

array([ 0, 3, 4, -1])

Engine中的HashTable

Engine对象的字典功能由mapping提供:

In [19]:

ht=e.mapping

print ht

In [53]:

ht.get_item('d')

Out[53]:

3

In [55]:

ht.lookup(np.array(['a','d','e','z'],'O'))

Out[55]:

array([ 0, 3, 4, -1])

值不的Index

当Index中的每个值都时,可以使用HashTable将值映射到其位置之上。若值不,则Pandas会采用两种较慢的算法。

值时,采用HashTable映射,复杂度为O(1),但需要额外的内存保存HashTable

值排序时使用二分搜索法,复杂度为O(log2(N))

值无序时则逐个比较,复杂度为O(N)

在Pandas的内部实现中,还考虑了内存的因素,因此对于较大的、排序的、值的Index,也会采用二分搜索法,省去了由HashTable带来的额外内存开销。

下面我们创建这三种Index对象:

In [80]:

N=10000

unique_keys = np.array(list(set(pd.core.common.rands(5) for i in xrange(N))), 'O')

duplicate_keys = unique_keys.copy()

duplicate_keys[-1] = duplicate_keys[0]

sorted_keys = np.sort(duplicate_keys)

unique_index = pd.Index(unique_keys)

sorted_index = pd.Index(sorted_keys)

duplicate_index = pd.Index(duplicate_keys)

to_search = unique_keys[N-2]

每个Index都有is_unique和is_monotonic属性,分别表示值是否,和是否排序。下面的程序显示上面三个Index对象的属性:

In [101]:

fromitertoolsimportproduct

def dataframe_fromfunc(func, index, columns):

return pd.DataFrame([[func(idx, col) for col in columns] for idx in index],

index = index, columns = columns)

predicates = ["is_unique", "is_monotonic"]

index = ["unique_index", "sorted_index", "duplicate_index"]

dataframe_fromfunc(lambda idx, pred:getattr(globals()[idx], pred), index, predicates)

Out[101]:

is_uniqueis_monotonic

unique_indexTrueFalse

sorted_indexFalseTrue

duplicate_indexFalseFalse

所有的Index都支持get_loc(),但只有值的Index才支持get_indexer()。三者的get_loc()方法所返回的位置信息也不同:

unique_index:由于值是的,因此返回一个整数

sorted_index:由于值是排序的,因此返回一个slice对象

duplicate_index:返回一个布尔数组

这三种返回值都可以作为下标存取ndarray中的值。

In [103]:

printunique_index.get_loc(unique_keys[0])

print sorted_index.get_loc(unique_keys[0])

print duplicate_index.get_loc(unique_keys[0])

slice(8528, 8530, None)

[ True False False ..., False False True]

下面比较三者的运算速度:

In [81]:

%timeitunique_index.get_loc(to_search)

1000000 loops, best of 3: 828 ns per loop

In [82]:

%timeitsorted_index.get_loc(to_search)

100000 loops, best of 3: 15.2 us per loop

In [83]:

%timeitduplicate_index.get_loc(to_search)

1000 loops, best of 3: 284 us per loop

分享好友

分享这个小栈给你的朋友们,一起进步吧。

星说
创建时间:2019-11-28 12:45:43
作为炎黄子孙,我们有很多知识渊博的祖人,这个祖人指的是在各领域登峰造极的学者论说,我们跟随强大基因的路线,学习,深化自己的知识体系,优化环境。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • unnamed persona
    栈主

小栈成员

查看更多
  • 外星人6
  • supergirlxu
  • unnamed person1
  • daxuesheng
戳我,来吐槽~