在pandas中扁平化Series,即元素为列表的Series
我有一个这样的序列:
s = Series([['a','a','b'],['b','b','c','d'],[],['a','b','e']])
看起来像这样:
0 [a, a, b]
1 [b, b, c, d]
2 []
3 [a, b, e]
dtype: object
我想统计一下我总共有多少个元素。 我尝试的一些简单方法,比如:
s.values.hist()
或者
s.values.flatten()
都没有成功。 我哪里做错了呢?
4 个回答
-1
我个人非常喜欢在数据框中使用数组,每个项目对应一列。这样做能让你拥有更多的功能。所以,我有一个替代的方法。
>>> raw = [['a', 'a', 'b'], ['b', 'b', 'c', 'd'], [], ['a', 'b', 'e']]
>>> df = pd.DataFrame(raw)
>>> df
Out[217]:
0 1 2 3
0 a a b None
1 b b c d
2 None None None None
3 a b e None
现在,看看每一行有多少个值。
>>> df.count(axis=1)
Out[226]:
0 3
1 4
2 0
3 3
在这里使用 sum()
函数就能得到你想要的结果。
其次,关于你在评论中提到的:获取分布。这里可能有更简洁的方法,但我还是更喜欢下面这个,而不是评论中给你的提示。
>>> foo = [col.value_counts() for x, col in df.iteritems()]
>>> foo
Out[246]:
[a 2
b 1
dtype: int64, b 2
a 1
dtype: int64, b 1
c 1
e 1
dtype: int64, d 1
dtype: int64]
foo
现在包含了每一列的分布。列的解释还是“第x个值”,也就是说第0列包含了你数组中所有“第一个值”的分布。
接下来的步骤是“把它们加起来”。
>>> df2 = pd.DataFrame(foo)
>>> df2
Out[266]:
a b c d e
0 2 1 NaN NaN NaN
1 1 2 NaN NaN NaN
2 NaN 1 1 NaN 1
3 NaN NaN NaN 1 NaN
>>> test.sum(axis=0)
Out[264]:
a 3
b 4
c 1
d 1
e 1
dtype: float64
需要注意的是,对于这些非常简单的问题,列表系列和每个项目都有列的数据框之间的区别不大,但一旦你想进行真正的数据处理,后者能提供更多的功能。此外,它可能更高效,因为你可以使用pandas的内部方法。
16
如果我们继续使用原问题中的 pandas Series,从 Pandas 0.25.0 版本开始,有一个很不错的选项就是 Series.explode() 方法。这个方法可以把列表“炸开”,变成多行数据,每一行的索引会重复。
原来的 Series 如下:
s = pd.Series([['a','a','b'],['b','b','c','d'],[],['a','b','e']])
我们来用这个方法“炸开”它,得到的 Series 中,索引会重复。这个索引表示的是原始列表中的位置。
>>> s.explode()
Out:
0 a
0 a
0 b
1 b
1 b
1 c
1 d
2 NaN
3 a
3 b
3 e
dtype: object
>>> type(s.explode())
Out:
pandas.core.series.Series
现在我们可以用 Series.value_counts() 来统计元素的数量:
>>> s.explode().value_counts()
Out:
b 4
a 3
d 1
c 1
e 1
dtype: int64
如果想要统计 NaN 值(缺失值),可以这样做:
>>> s.explode().value_counts(dropna=False)
Out:
b 4
a 3
d 1
c 1
e 1
NaN 1
dtype: int64
最后,使用 Series.plot() 来绘制直方图:
>>> s.explode().value_counts(dropna=False).plot(kind = 'bar')
2
s.map(len).sum()
这个方法很好用。s.map(len)
会对每个元素使用 len()
函数,计算出每个元素的长度,然后返回一个包含所有长度的列表。接着,你只需要对这个列表使用 sum
函数,就能得到所有长度的总和。