如何用Pandas内置方法求字符串Series或GroupBy对象的中位数
问题:如何在不完整排序的情况下找到字符串列的字典序中位值?
我有一个美国婴儿姓名数据集,其中包含Name列。需要基于姓名的字典序找到该列的中位姓名,但不想通过完全排序整个列的方式实现。尝试使用Pandas内置的median()方法并设置numeric_only=False,但触发错误:TypeError: could not convert string to float: 'Emma'。想知道操作是否有误,或者有没有合适的内置方法?
数据集片段
,Id,Name,Year,Gender,State,Count 11349,11350,Emma,2004,F,AK,62 11350,11351,Madison,2004,F,AK,48 11351,11352,Hannah,2004,F,AK,46 11352,11353,Grace,2004,F,AK,44 11353,11354,Emily,2004,F,AK,41 11354,11355,Abigail,2004,F,AK,37
尝试的代码
import pandas as pd baby_names = pd.read_csv( "Pandas_DataMart\DataMart\06_Stats\US_Baby_Names\US Baby Names.xlsx") print(baby_names['Name'].median(numeric_only=False))
完整错误信息
Traceback (most recent call last): File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\nanops.py", line 720, in nanmedian values = values.astype("f8") ValueError: could not convert string to float: 'Emma' 上述异常是以下异常的直接原因: Traceback (most recent call last): File "c:\Users\...\BabyNames.py", line 18, in <module> print(baby_names['Name'].median(numeric_only=False)) File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\generic.py", line 10802, in median return NDFrame.median(self, axis, skipna, level, numeric_only, **kwargs) File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\generic.py", line 10374, in median return self._stat_function( File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\generic.py", line 10354, in _stat_function return self._reduce( File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\series.py", line 4392, in _reduce return op(delegate, skipna=skipna, **kwds) File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\nanops.py", line 156, in f result = alt(values, axis=axis, skipna=skipna, **kwds) File "C:\Users\JohnDoe\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\nanops.py", line 723, in nanmedian raise TypeError(str(err)) from err TypeError: could not convert string to float: 'Emma'
解答
为什么median()方法不可行?
Pandas的median()方法本质是为数值型数据设计的,即使设置numeric_only=False,其底层逻辑仍然会尝试将数据转换为浮点型进行计算,字符串类型无法完成这个转换,因此触发错误。该方法不支持基于字典序的字符串中位值计算。
高效的替代方案:使用nsmallest()/nlargest()
Pandas的nsmallest(n, column)方法内部使用堆排序算法,无需对整个数据集进行完全排序(时间复杂度为O(n),远优于全排序的O(nlogn)),可以高效找到第n小的元素,正好符合你的需求。
步骤:
- 计算数据集
Name列的长度,确定中位位置:- 如果总长度为奇数,中位位置为
len(series) // 2(索引从0开始) - 如果总长度为偶数,可选择中间两个元素中的任意一个(比如取第
len(series)//2 -1或len(series)//2个)
- 如果总长度为奇数,中位位置为
- 使用
nsmallest()获取对应位置的元素
示例代码:
import pandas as pd # 读取正确的CSV文件(修正原代码中xlsx的错误) baby_names = pd.read_csv("https://raw.githubusercontent.com/guipsamora/pandas_exercises/master/06_Stats/US_Baby_Names/US_Baby_Names_right.csv") name_series = baby_names['Name'] n = len(name_series) # 计算中位位置并获取中位姓名 if n % 2 == 1: median_pos = n // 2 median_name = name_series.nsmallest(median_pos + 1).iloc[-1] else: # 偶数长度时取中间第二个元素,可根据需求调整为第一个 median_pos = n // 2 median_name = name_series.nsmallest(median_pos + 1).iloc[-1] print("字典序中位姓名:", median_name)
说明:
nsmallest(k)会返回前k个最小的元素(按字典序),取最后一个元素就是第k小的元素- 这种方法避免了全排序,性能更优,尤其是在数据集较大时
内容的提问来源于stack exchange,提问作者MJK
相关产品推荐
相关产品推荐

