问题
有存在随机的10000个数据,请用Python将判断每个数在哪个区间,并输出,区间分为,小于0,0到50,50到100,100 到1000,1000以上。
import pandas as pd
# 创建一个示例dataframe
data = {'values': [随机数据]} # 这里用一个列表来表示10000个随机数
df = pd.DataFrame(data)
# 定义每个区间的边界值
boundaries = [-1, 0, 50, 100, 1000, 10000]
# 初始化一个空列表,用于存储每个数所在的区间
intervals = []
# 遍历dataframe的每一行
for i, row in df.iterrows():
value = row['values']
# 遍历每个区间的边界值
for j, bound in enumerate(boundaries):
# 如果数小于或等于边界值,则判断为该区间
if value <= bound:
intervals.append(f"小于{bound}")
break
else:
# 如果数不在前五个区间,则判断为1000以上
intervals.append("1000以上")
# 输出结果
for i, interval in enumerate(intervals):
print(f"数字{df['values'][i]}位于区间:{interval}")
详解
-
iterrows() 的用法:
iterrows是pandas中的一个函数,用于在DataFrame中进行遍历,逐行返回一个元组index和Series。(需要注意的是,每个元组包含该行的索引和行数据。而行数据是Series类型。)import pandas as pd data = {'Column 1': [1, 2, 3, 4], 'Column 2': ['A', 'B', 'C', 'D'], 'Column 3': [10, 20, 30, 40]} df = pd.DataFrame(data) for index, row in df.iterrows(): print(f"Index: {index}, Row data: {row}")
输出结果:
Index: 0, Row data: Column 1 1 Column 2 A Column 3 10 Name: 0, dtype: object Index: 1, Row data: Column 1 2 Column 2 B Column 3 20 Name: 1, dtype: object Index: 2, Row data: Column 1 3 Column 2 C Column 3 30 Name: 2, dtype: object Index: 3, Row data: Column 1 4 Column 2 D Column 3 40 Name: 3, dtype: object
-
enumerate() 的用法:
enumerate
是Python内置函数,可以用于在遍历一个可迭代的对象时,同时返回一个计数和相应的值。
在处理DataFrame中的行时,可以使用enumerate
函数获取每个行的序号并进行相应的处理。import pandas as pd df = pd.DataFrame({'ID': [1, 2, 3], 'Name': ['Tom', 'Jerry', 'Mike'], 'Age': [20, 22, 18]}) # 使用`enumerate`遍历DataFrame数据,并输出每行数据的序号和'Name'列数据: for i, data in enumerate(df['Name']): print(i, data)
输出结果:
0 Tom 1 Jerry 2 Mike
需要注意的是,
enumerate
返回的是一个元组(index, value)
,其中index就是每一行对应的序号,value是该行的数据。同时,我们也可以在for循环里面使用enumerate函数遍历DataFrame数据的行,使用iterrows
不一样的是,for循环在每次迭代时不会创建一个Series类型的对象。
5种优化方法
和使用iterrows
一样,使用enumerate
遍历单个行仍然是一种非常慢的方法,因此,我们还是应该尽可能使用pandas内置的矢量化的操作,而不是循环行遍历DataFrame来优化DataFrame操作。
注意
cut函数无法直接处理开放区间的上界,可以用 float('inf')
或np.inf
来表示正无穷大。且cut的bins长度必须大于labels 的长度。
法1
pd.cut()
import numpy as np
import pandas as pd#创建10000个随机数字
arr = np.random.rand(10000) * 3000
#创建区间范围
bins = [-np.inf, 0, 50, 100, 1000, np.inf]
#给区间加上标签
labels = ['<0', '0-50', '50-100', '100-1000', '>1000']
#将数字分组
result =pd.cut(arr, bins, labels = labels)
#统计每个区间内的数字数量
count = pd.value_counts(result)
#输出结果
print(count)
在使用pd.cut()
函数时,它会返回一个用于后续分类数据统计的Categorical
类型,该类型支持一些常见的操作。其中,pd.cut()
函数的第一个参数是指定需要转化为分类变量的变量,第二个参数则是指定用于分的数值区间,第三个参数是区间对应的名称数组。
法2
np.digitize()
函数将数字分组到不同的区间
import numpy as np
import pandas as pd
#创建10000个随机数字
arr = np.random.rand(10000) * 3000
#创建区间范围
bins = [-np.inf, 0, 50, 100, 1000, np.inf]
#给区间加上标签
labels = ['<0', '0-50', '50-100', '100-1000', '>1000']
#将数字分组并标记标签
result = labels[np.digitize(arr, bins)]
#统计每个区间内的数字数量
count = pd.value_counts(result)
#输出结果
print(count)
这个例子和使用pd.cut()
函数类似。区别在于np.digitize()
函数可以将数据组分成指定的分组,并返回一个表示分组索引的数组,然后使用索引数组标记出每个数所在的区间并返回所在的标签列表。
需要注意的是,在使用np.digitize()
函数时,如果存在较小的值或较大的值,需要在去向数组bins
的值中添加无穷的边界值(-np.Inf
和np.Inf
)。同时,应该掌握不同函数之间的比较,选择最合适自己的方式。
法3
np.where()函数:
import numpy as np
import pandas as pd
# 创建10000个随机数字
arr = np.random.rand(10000) * 3000
# 定义区间边界值
bins = [0, 50, 100, 1000, np.inf]
# 给区间添加标签
labels = ['0-50', '50-100', '100-1000', '>1000']
# 利用np.where()函数实现分组
result = np.where(arr <= 0, '<0', pd.cut(arr, bins, labels=labels))
# 统计每个区间内的数字数量
count = pd.value_counts(result)
# 输出结果
print(count)
这个示例使用了np.where()
函数根据条件筛选出每个数字属于的数据区间,并返回对应的标签。如果数字小于等于0,则返回’<0’,否则根据pd()
函数分组。
法4
np.select()函数:
import numpy as np
import pandas as pd
# 创建10000个随机数字
arr = np.random.rand(10000) * 3000
# 定义区间边界值
bins = [0, 50, 100, 1000, np.inf]
# 给区间添加标签
labels = ['0-50', '50-100', '100-1000', '>1000']
# 利用np.select()函数实现分组
conditions = [arr <= 0, (arr > 0) & (arr <= 50), (arr > 50) & (arr <= 100), (arr > 100) & (arr <= 1000), arr > 1000]
result = np.select(conditions, labels, default='<0')
# 统计每个区间内的数字数量
count = pd.value_counts(result)
# 输出结果
print(count)
该示例使用了np.select()
函数,利用多个条件将每个数字分配到对应的标签中,并设置了default参数,当条件都不满足时返回’<0’。最后使用pd.value_counts()
函数统计每个区间内数字的数量。
法5
pd.cut()+groupby()函数:
import numpy as np
import pandas as pd
# 创建10000个随机数字
arr = np.random.rand(10000) * 3000
# 定义区间边界值
bins = [0, 50, 100,1000, np.inf]
# 给区间添加标签
labels = ['0-50 '50-100', '100-1000', '>1000']
# 使用pd.cut()函数进行分组
result = pd.cut(arr, bins=bins, labels=labels, right=False)
# 使用groupby()函数进行分组并计数
count = result.groupby(result).size()
# 输出结果
print(count)
该示例直接使用pd.cut()
函数对数组进行分组,并设置了right参数为False,表示不包含右边界。然后使用groupby()
函数对分组结果进行统计,并输出个区间内的数字数量。
针对Dataframe格式的数据的写法
下面将前面提到的其他 4 种写法应用到 DataFrame 格式的数据中,并返回每组数据的数量值。需要注意的是,除了 pd.cut() 函数,其他函数需要将每个条件赋值给新列,再对新列进行统计。
import numpy as
import pandas as pd
# 创建 DataFrame 格式的数据
df = pd.DataFrame(np.random.rand(10000, 2) * 3000, columns=['col1', 'col2'])
# 定义区间边界值
bins = [0, 50, 100, 1000, np.inf]
# 给区间添加标签
labels = ['0-50', '50-100', '100-1000', '>1000']
# pd.cut()函数分组方法
df['cut_group'] = pd.cut(df['col1'], bins=bins, labels=labels, right=False)
count1 = df['cut_group'].value_counts()
print('cut方法统计结果:\n', count1)
# np.where()函数组方法
df['where_group'] = np.where(df['col1'] <= 0, '<0', pd.cut(df['col1'], bins=bins, labels=labels))
count2 = df['where_group'].value_counts()
print('where方法统计结果:\n', count2)
# np.select()函数分组方法
conditions = [df['col1'] <= 0, (df['col1'] > 0) & (df['col1'] <= 50), (df['col1'] > 50) & (df['col1'] <= 100), (df['col1'] > 100 & (df['col1'] <= 1000), df['col1'] > 100]
choices = ['<0', '0-50', '50-100', '100-1000', '>1000']
df['select_group'] = np.select(conditions, choices, default='<0')
count3 = df['select_group'].value_counts()
print('select方法统计结果:\n', count3)
# apply()函数分组方法
df['apply_group'] = df['col1'].apply(lambda x: labels[bisect.bisect_left(b, x)])
count4 = df['apply_group'].value_counts()
print('apply方法统计结果:\n', count4)
执行以上代码,分别使用了 pd.cut(),np.where(),np.select() 和 apply() 这些方法来统计 col1一列分组后的数据量,各方法的返回值 count1、count2、count3、count4 分别储存在 DataFrame 中。
对于 apply() 方法需要添加 bisect 调用,即 from bisect import bisect。最后使用 print 语句输出各方法的统计结果,类型为 Series。
常见的矢量化操作
- apply函数:对数据集中的每一行或应用函数,相较于循环操作可以更高效地执行矢量化函数操作。
- groupby函数:根据某一列或多列对数据集进行分组,然后可以应用聚合函数如.mean()、.sum()等计算每组统计量。
- merge函数和concat函数:用于组合或合并不同的数据集。
- str方法:字符串函数,用于在一列或多列中应用字符串函数。
- rolling和expanding函数:用于时间序列数据的聚合运算,例如,移动平均和指数平均。
- pd.cut函数和pd.qcut函数:用于将数据离散化,将连续的数据转换成离散的数据,可以用于数据的分析和可视化。
- isin函数和str.contains函数:用于根据条件从DataFrame中筛选行或列。
- pivot_table函数和melt函数:用于实现长/宽数据格式之间的转换。
补充
- 数据结构操作:
append(): 添加一个或多个数据帧或Series到另一个数据帧。
concat(): 连接多个数据帧或Series。
merge(): 用于合并数据帧。
pivot_table(): 创建一个数据透视表。
stack(): 将数据帧的列堆叠为行。
unstack(): 将数据帧的行拆分为列。 - 数据处理操作:
drop(): 删除数据帧的列或行。
fillna(): 填充数据帧中的缺失值。
interpolate(): 插值处理数据帧中的缺失值。
isna(): 检查数据帧中的值是否为缺失值。
notna(): 检查数据帧中的值是否不为缺失值。
replace(): 替换数据帧中的值。
shift(): 移动数据帧的列。
roll(): 滚动数据帧的列。
agg(): 对数据帧的列应用聚合函数。
apply(): 对数据帧的行或列应用自定义函数。
transform(): 对数据帧的列应用转换函数。 - 排序和筛选:
sort_values(): 按值对数据帧进行排序。
sort_index(): 按索引对数据帧进行排序。
groupby(): 对数据帧进行分组。
filter(): 应用筛选函数。 - 其他操作:
assign(): 给数据帧添加新的列。
astype(): 转换数据帧的列的数据类型。
itertuples(): 返回一个迭代器,生成数据帧的行。
loc[]: 通过行和列的标签获取数据。
iloc[]: 通过整数位置获取数据。
这些操作大多数都是矢量化的,这意味着它们会在整个数据结构上同时应用,而不会逐个处理数据。这种特性使得 Pandas 非常高效,特别是对于大规模的数据处理任务。