将随机列表中的项目附加到新列表
append items from shuffled list to a new list
对于文本分类项目(年龄),我正在制作我的数据的一个子集。我制作了 3 个文件名列表,按年龄排序。我想打乱这些列表,然后将每个打乱后的列表中的 5000 个文件名附加到一个新列表中。结果应该是一个包含 15000 个文件的数据子集(5000 个 10 秒、5000 个 20 秒、5000 个 30 秒)。在下面你可以看到我到目前为止所写的内容。但是我知道 random.shuffle
returns none 和 none 类型的对象是不可迭代的。我怎么解决这个问题?
def seed():
return 0.47231099848
teens = [list of files]
tweens = [list of files]
thirthies = [list of files]
data = []
for categorie in random.shuffle([teens, tweens, thirthies],seed):
data.append(teens[:5000])
data.append(tweens[:5000])
data.append(thirthies[:5000])
shuffle
returnsNone
,不可迭代
你应该做的
data = []
for category in [teens, tweens, thirthies]:
category_copy = category[:]
random.shuffle(category_copy, seed)
data.append(category_copy[:5000])
random.shuffle
更改列表本身(使其随机排列)。所以看起来你想要这样的东西:
teens = [list of files]
tweens = [list of files]
thirthies = [list of files]
random.shuffle(teens)
random.shuffle(tweens)
random.shuffle(thirthies)
data = []
for categorie in [teens, tweens, thirthies] :
data.append(categorie[:5000])
顺便说一句,somelist[:n]
将被截断为 n
个元素,请检查:
>>> [1,2,3,4,5][:3]
[1, 2, 3]
第一个问题是您正在打乱由 3 个项目 [teens, tweens, thirthies] 组成的列表(甚至每个项目都是一个列表)而不是打乱每个子列表
其次,您可以使用 random.sample
而不是 random.shuffle
for categ in [teens, tweens, thirthies]:
data.append(random.sample(categ,5000])
或者按照@JonClements 在评论中的建议,您可以使用列表理解
categories = [teens, tweens, thirthies]
data = [e for categ in categories for e in random.sample(categ, 5000)]
你说得对 random.shuffle
returns None。那是因为它就地打乱了它的列表参数,并且它是一个 Python 约定,函数接受一个可变的 arg 并改变它 return None
。但是,您误解了 random
arg 到 random.shuffle
:它需要是一个随机数生成器,而不是像您的 seed
那样总是 return 相同数字的函数。
顺便说一句,您可以使用其 seed
函数为随机模块提供的标准随机数生成器提供种子。 random.seed
接受任何可哈希对象作为其参数,尽管通常将其传递给数字或字符串。你也可以传递它 None
(这相当于根本不传递一个 arg),它会用系统随机源为随机发生器播种(如果没有系统随机源,那么系统时间用作种子)。如果在导入random模块后没有显式调用seed
,相当于调用seed()
提供种子的好处是,每次您的 运行 程序使用相同的种子时,各种随机模块函数产生的随机数将完全相同。这在开发和调试代码时非常有用:当输出不断变化时,很难追踪错误。 :)
有两种主要的方式来做你想做的事。您可以打乱列表,然后从中切出前 5000 个文件名。或者您可以使用 random.sample
函数随机抽取 5000 个样本。这样你就不需要打乱整个列表。
import random
random.seed(0.47231099848)
# teens, tweens, thirties are lists of file names
file_lists = [teens, tweens, thirties]
# Shuffle
data = []
for flist in file_lists:
random.shuffle(flist)
data.append(flist[:5000])
使用sample
# Sample
data = []
for flist in file_lists:
data.append(random.sample(flist, 5000))
我没有对这段代码进行速度测试,但我怀疑 sample
会更快,因为它只需要随机 select 项而不是移动所有列表项。 shuffle
相当高效,因此您可能不会注意到 运行 时间有太大差异,除非您的十几岁、十几岁和三十多岁的文件列表每个都有超过 5000 个文件名。
这两个循环都使 data
成为一个包含 3 个子列表的嵌套列表,每个子列表中有 5000 个文件名。但是,如果您希望它是 15000 个文件名的平面列表,您只需要使用 list.extend
方法而不是 list.append
。例如,
data = []
for flist in file_lists:
data.extend(random.sample(flist, 5000))
或者我们可以使用带有双 for
循环的列表推导式来做到这一点:
data = [fname for flist in file_lists for fname in random.sample(flist, 5000)]
如果您需要过滤 data
的内容来构建您的最终文件列表,最简单的方法是在列表理解中添加一个 if
条件。
假设我们有一个函数可以测试文件名是否是我们想要保留的文件名:
def keep_file(fname):
# if we want to keep fname, return True, otherwise return False
那我们可以做
data = [fname for flist in file_lists for fname in random.sample(flist, 5000) if keep_file(fname)]
和data
将只包含通过keep_file
测试的文件名。
另一种方法是使用生成器表达式而不是列表理解来创建文件名,然后将其传递给内置 filter
函数:
data_gen = filter(keep_file, (fname for flist in file_lists for fname in random.sample(flist, 5000)))
data_gen
本身就是一个迭代器。您可以像这样从中构建一个列表:
data_final = list(data_gen)
或者如果您实际上不需要将所有名称作为一个集合,您可以将它们一个接一个地处理,您可以将其放入一个 for
循环中,如下所示:
for fname in data_gen:
print(fname)
# Do other stuff with fname
这使用较少的 RAM,但缺点是它 "consumes" 文件名,所以一旦 for
循环完成后 data_gen
将是空的。
假设您编写了一个从每个文件中提取所需数据的函数:
def age_and_text(fname):
# Do stuff that extracts the age and desired text from the file
return fname, age, text
您可以像这样创建那些 (filename, age, text)
元组的列表:
data_gen = (fname for flist in file_lists for fname in random.sample(flist, 5000) if keep_file(fname))
final_data = [age_and_text(fname) for fname in data_gen]
请注意我的第一个片段中的切片:flist[:5000]
。这需要 flist
中的前 5000 个项目,索引从 0 到 4999 的项目。您的版本有 teens[:5001]
,这是一个差一错误。切片的工作方式与范围相同。因此 range(5000)
产生从 0 到 4999 的 5000 个数字。它之所以这样工作是因为 Python(像大多数现代编程语言一样)使用从零开始的索引。
对于文本分类项目(年龄),我正在制作我的数据的一个子集。我制作了 3 个文件名列表,按年龄排序。我想打乱这些列表,然后将每个打乱后的列表中的 5000 个文件名附加到一个新列表中。结果应该是一个包含 15000 个文件的数据子集(5000 个 10 秒、5000 个 20 秒、5000 个 30 秒)。在下面你可以看到我到目前为止所写的内容。但是我知道 random.shuffle
returns none 和 none 类型的对象是不可迭代的。我怎么解决这个问题?
def seed():
return 0.47231099848
teens = [list of files]
tweens = [list of files]
thirthies = [list of files]
data = []
for categorie in random.shuffle([teens, tweens, thirthies],seed):
data.append(teens[:5000])
data.append(tweens[:5000])
data.append(thirthies[:5000])
shuffle
returnsNone
,不可迭代
你应该做的
data = []
for category in [teens, tweens, thirthies]:
category_copy = category[:]
random.shuffle(category_copy, seed)
data.append(category_copy[:5000])
random.shuffle
更改列表本身(使其随机排列)。所以看起来你想要这样的东西:
teens = [list of files]
tweens = [list of files]
thirthies = [list of files]
random.shuffle(teens)
random.shuffle(tweens)
random.shuffle(thirthies)
data = []
for categorie in [teens, tweens, thirthies] :
data.append(categorie[:5000])
顺便说一句,somelist[:n]
将被截断为 n
个元素,请检查:
>>> [1,2,3,4,5][:3]
[1, 2, 3]
第一个问题是您正在打乱由 3 个项目 [teens, tweens, thirthies] 组成的列表(甚至每个项目都是一个列表)而不是打乱每个子列表
其次,您可以使用 random.sample
而不是 random.shuffle
for categ in [teens, tweens, thirthies]:
data.append(random.sample(categ,5000])
或者按照@JonClements 在评论中的建议,您可以使用列表理解
categories = [teens, tweens, thirthies]
data = [e for categ in categories for e in random.sample(categ, 5000)]
你说得对 random.shuffle
returns None。那是因为它就地打乱了它的列表参数,并且它是一个 Python 约定,函数接受一个可变的 arg 并改变它 return None
。但是,您误解了 random
arg 到 random.shuffle
:它需要是一个随机数生成器,而不是像您的 seed
那样总是 return 相同数字的函数。
顺便说一句,您可以使用其 seed
函数为随机模块提供的标准随机数生成器提供种子。 random.seed
接受任何可哈希对象作为其参数,尽管通常将其传递给数字或字符串。你也可以传递它 None
(这相当于根本不传递一个 arg),它会用系统随机源为随机发生器播种(如果没有系统随机源,那么系统时间用作种子)。如果在导入random模块后没有显式调用seed
,相当于调用seed()
提供种子的好处是,每次您的 运行 程序使用相同的种子时,各种随机模块函数产生的随机数将完全相同。这在开发和调试代码时非常有用:当输出不断变化时,很难追踪错误。 :)
有两种主要的方式来做你想做的事。您可以打乱列表,然后从中切出前 5000 个文件名。或者您可以使用 random.sample
函数随机抽取 5000 个样本。这样你就不需要打乱整个列表。
import random
random.seed(0.47231099848)
# teens, tweens, thirties are lists of file names
file_lists = [teens, tweens, thirties]
# Shuffle
data = []
for flist in file_lists:
random.shuffle(flist)
data.append(flist[:5000])
使用sample
# Sample
data = []
for flist in file_lists:
data.append(random.sample(flist, 5000))
我没有对这段代码进行速度测试,但我怀疑 sample
会更快,因为它只需要随机 select 项而不是移动所有列表项。 shuffle
相当高效,因此您可能不会注意到 运行 时间有太大差异,除非您的十几岁、十几岁和三十多岁的文件列表每个都有超过 5000 个文件名。
这两个循环都使 data
成为一个包含 3 个子列表的嵌套列表,每个子列表中有 5000 个文件名。但是,如果您希望它是 15000 个文件名的平面列表,您只需要使用 list.extend
方法而不是 list.append
。例如,
data = []
for flist in file_lists:
data.extend(random.sample(flist, 5000))
或者我们可以使用带有双 for
循环的列表推导式来做到这一点:
data = [fname for flist in file_lists for fname in random.sample(flist, 5000)]
如果您需要过滤 data
的内容来构建您的最终文件列表,最简单的方法是在列表理解中添加一个 if
条件。
假设我们有一个函数可以测试文件名是否是我们想要保留的文件名:
def keep_file(fname):
# if we want to keep fname, return True, otherwise return False
那我们可以做
data = [fname for flist in file_lists for fname in random.sample(flist, 5000) if keep_file(fname)]
和data
将只包含通过keep_file
测试的文件名。
另一种方法是使用生成器表达式而不是列表理解来创建文件名,然后将其传递给内置 filter
函数:
data_gen = filter(keep_file, (fname for flist in file_lists for fname in random.sample(flist, 5000)))
data_gen
本身就是一个迭代器。您可以像这样从中构建一个列表:
data_final = list(data_gen)
或者如果您实际上不需要将所有名称作为一个集合,您可以将它们一个接一个地处理,您可以将其放入一个 for
循环中,如下所示:
for fname in data_gen:
print(fname)
# Do other stuff with fname
这使用较少的 RAM,但缺点是它 "consumes" 文件名,所以一旦 for
循环完成后 data_gen
将是空的。
假设您编写了一个从每个文件中提取所需数据的函数:
def age_and_text(fname):
# Do stuff that extracts the age and desired text from the file
return fname, age, text
您可以像这样创建那些 (filename, age, text)
元组的列表:
data_gen = (fname for flist in file_lists for fname in random.sample(flist, 5000) if keep_file(fname))
final_data = [age_and_text(fname) for fname in data_gen]
请注意我的第一个片段中的切片:flist[:5000]
。这需要 flist
中的前 5000 个项目,索引从 0 到 4999 的项目。您的版本有 teens[:5001]
,这是一个差一错误。切片的工作方式与范围相同。因此 range(5000)
产生从 0 到 4999 的 5000 个数字。它之所以这样工作是因为 Python(像大多数现代编程语言一样)使用从零开始的索引。