我正在尝试制作一个安装脚本,能够为我设置一个工作区,这样我就不需要手动完成了。 我开始在bash中这样做,但很快就意识到这样做不会那么好。
我的下一个想法是使用python来做,但似乎无法以正确的方式做到这一点。我的想法是创建一个列表(列表是一个带有所有数据文件路径的.txt文件),将此列表随机播放,然后根据比例将每个文件移动到我的火车目录或测试目录....
但这是python,有没有更简单的方法来做到这一点,似乎我正在做一个ullsary解决方法只是为了分割文件。
Bash代码:
dict
我的问题是最后一部分。由于我随机选择数字,我不确定数据是否会按照希望进行分区,我的最后一条if语句是检查分区是否正确,如果没有则再修复..这是不可能的,因为我正在检查浮点数,一般来说解决方案更像是一个快速解决方案。
答案 0 :(得分:8)
scikit-learn
来救援=)
>>> import numpy as np
>>> from sklearn.cross_validation import train_test_split
>>> X, y = np.arange(10).reshape((5, 2)), range(5)
>>> X
array([[0, 1],
[2, 3],
[4, 5],
[6, 7],
[8, 9]])
>>> y
[0, 1, 2, 3, 4]
# If i want 1/4 of the data for testing
# and i set a random seed of 42.
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
>>> X_train
array([[4, 5],
[0, 1],
[6, 7]])
>>> X_test
array([[2, 3],
[8, 9]])
>>> y_train
[2, 0, 3]
>>> y_test
[1, 4]
请参阅http://scikit-learn.org/stable/modules/generated/sklearn.cross_validation.train_test_split.html
演示:
alvas@ubi:~$ mkdir splitfileproblem
alvas@ubi:~$ cd splitfileproblem/
alvas@ubi:~/splitfileproblem$ mkdir original
alvas@ubi:~/splitfileproblem$ mkdir train
alvas@ubi:~/splitfileproblem$ mkdir test
alvas@ubi:~/splitfileproblem$ ls
original train test
alvas@ubi:~/splitfileproblem$ cd original/
alvas@ubi:~/splitfileproblem/original$ ls
alvas@ubi:~/splitfileproblem/original$ echo 'abc' > a.txt
alvas@ubi:~/splitfileproblem/original$ echo 'def\nghi' > b.txt
alvas@ubi:~/splitfileproblem/original$ cat a.txt
abc
alvas@ubi:~/splitfileproblem/original$ echo -e 'def\nghi' > b.txt
alvas@ubi:~/splitfileproblem/original$ cat b.txt
def
ghi
alvas@ubi:~/splitfileproblem/original$ echo -e 'jkl' > c.txt
alvas@ubi:~/splitfileproblem/original$ echo -e 'mno' > d.txt
alvas@ubi:~/splitfileproblem/original$ ls
a.txt b.txt c.txt d.txt
在Python中:
alvas@ubi:~/splitfileproblem$ ls
original test train
alvas@ubi:~/splitfileproblem$ python
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> from sklearn.cross_validation import train_test_split
>>> os.listdir('original')
['b.txt', 'd.txt', 'c.txt', 'a.txt']
>>> X = y= os.listdir('original')
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
>>> X_train
['a.txt', 'd.txt', 'b.txt']
>>> X_test
['c.txt']
现在移动文件:
>>> for x in X_train:
... os.rename('original/'+x , 'train/'+x)
...
>>> for x in X_test:
... os.rename('original/'+x , 'test/'+x)
...
>>> os.listdir('test')
['c.txt']
>>> os.listdir('train')
['b.txt', 'd.txt', 'a.txt']
>>> os.listdir('original')
[]
答案 1 :(得分:2)
这是第一个干切解决方案,纯Python:
import sys, random, os
def splitdirs(files, dir1, dir2, ratio):
shuffled = files[:]
random.shuffle(shuffled)
num = round(len(shuffled) * ratio)
to_dir1, to_dir2 = shuffled[:num], shuffled[num:]
for d in dir1, dir2:
if not os.path.exists(d):
os.mkdir(d)
for file in to_dir1:
os.symlink(file, os.path.join(dir1, os.path.basename(file)))
for file in to_dir2:
os.symlink(file, os.path.join(dir2, os.path.basename(file)))
if __name__ == '__main__':
if len(sys.argv) != 5:
sys.exit('Usage: {} files.txt dir1 dir2 ratio'.format(sys.argv[0]))
else:
files, dir1, dir2, ratio = sys.argv[1:]
ratio = float(ratio)
files = open(files).read().splitlines()
splitdirs(files, dir1, dir2, ratio)
[thd@aspire ~]$ python ./test.py ./files.txt dev tst 0.4
files.txt中列出的40%用于dev dir,60%用于tst
如果您需要真实文件,则会生成symliks而不是copy,将os.symlink
更改为shutil.copy2
答案 2 :(得分:2)
这是一个使用bash的$RANDOM
将事物移动到两个目标目录之一的简单示例。
$ touch {1..10}
$ mkdir red blue
$ a=(*/)
$ RANDOM=$$
$ for f in [0-9]*; do mv -v "$f" "${a[$((RANDOM/(32768/${#a[@]})))]}"; done
1 -> red/1
10 -> red/10
2 -> blue/2
3 -> red/3
4 -> red/4
5 -> red/5
6 -> red/6
7 -> blue/7
8 -> blue/8
9 -> blue/9
此示例从创建10个文件和两个目标目录开始。它将数组设置为*/
,扩展为"当前目录中的所有目录"。然后它运行一个for循环,看起来像是线噪声。我会把它分开,因为你。
"${a[$((RANDOM/(32768/${#a[@]})+1))]}"
是:
${a[
...数组" a",$((...))
...其下标是整数数学函数。$RANDOM
是一个bash变量,它生成从0到32767的ramdom(ish)数字,我们的公式将该比率的分母除以:${#a[@]}
,有效地将RANDOM/32768
乘以数组中的元素数量" a"。所有这一切的结果是我们选择一个随机数组元素,a.k.a。一个随机目录。
如果您真的希望使用"文件列表",并假设您将潜在目标列表保留在数组" a"中,则可以将for循环替换为一个循环:
while read f; do
mv -v "$f" "${a[$((RANDOM/(32768/${#a[@]})))]}"
done < /dir/file.txt
现在......这些解决方案可以平均分配结果&#34;这就是当你乘以分母时会发生什么。而且因为他们是随机的,所以没有办法确保你的random numbers won't put all your files into a single directory。因此,为了获得分裂,您需要更具创造性。
让我们假设我们只处理两个目标(因为我认为这就是你正在做的事情)。如果您正在寻找25/75分割,请相应地切分随机数范围。
$ declare -a b=([0]="red/" [8192]="blue/")
$ for f in {1..10}; do n=$RANDOM; for i in "${!b[@]}"; do [ $i -gt $n ] && break; o="${b[i]}"; done; mv -v "$f" "$o"; done
为便于阅读而破碎,这是我们所得到的,并附有评论:
declare -a b=([0]="red/" [8192]="blue/")
for f in {1..10}; do # Step through our files...
n=$RANDOM # Pick a random number, 0-32767
for i in "${!b[@]}"; do # Step through the indices of the array of targets
[ $i -gt $n ] && break # If the current index is > than the random number, stop.
o="${b[i]}" # If we haven't stopped, name this as our target,
done
mv -v "$f" "$o" # and move the file there.
done
我们使用数组的索引定义我们的分割。 8192是32767的25%,$ RANDOM的最大值。你可以在这个范围内分割你想要的东西,包括超过2个。
如果要测试此方法的结果,则计算数组中的结果是一种方法。让我们构建一个shell函数来帮助测试。
$ tester() { declare -A c=(); for f in {1..10000}; do n=$RANDOM; for i in "${!b[@]}"; do [ $i -gt $n ] && break; o="${b[i]}"; done; ((c[$o]++)); done; declare -p c; }
$ declare -a b='([0]="red/" [8192]="blue/")'
$ tester
declare -A c='([blue/]="7540" [red/]="2460" )'
$ b=([0]="red/" [10992]="blue/")
$ tester
declare -A c='([blue/]="6633" [red/]="3367" )'
在第一行,我们定义我们的功能。第二行设置&#34; b&#34;使用25/75分割的数组,然后我们运行该函数,其输出是计数器数组。然后我们重新定义了&#34; b&#34;具有33/67分割(或左右)的数组,并再次运行该函数以显示结果。
所以...虽然你肯定可以使用python,但你几乎可以肯定用bash和一点点数学来达到你所需要的。