Wszystko jest w tytule. Zastanawiam się, czy ktokolwiek zna się na szybką i rozsądną pamięć, wymaga losowego miksowania wszystkich linii pliku z 3 milionami linii. Domyślam się, że nie jest to możliwe za pomocą prostej komendy vim, więc każdy prosty skrypt używa Pythona. Próbowałem z Pythonem przy użyciu generatora liczb losowych, ale nie udało mi się znaleźć prostego wyjścia.Losowe łączenie linii pliku o wartości 3 milionów wierszy
Odpowiedz
import random
with open('the_file','r') as source:
data = [ (random.random(), line) for line in source ]
data.sort()
with open('another_file','w') as target:
for _, line in data:
target.write(line)
To powinno wystarczyć. 3 miliony linii zmieści się w pamięci większości maszyn, chyba że linie są OGROMNE (ponad 512 znaków).
3 miliony linii z przeciętnymi 80 znakami na linię będzie wynosić około 240 M bajtów, co jest ogromne do załadowania pliku w pamięci. –
@ Vikram.exe. Nie całkiem. To urządzenie ma 4 GB pamięci. 240M to nic. –
@ S.Lott, tak, zgadzam się, że nic, ale zastanawiałem się, czy możemy to zrobić, jak (przy niewielkim wysiłku), bez ładowania całego pliku w pamięci. –
zajmuje tylko kilka sekund w Pythonie:
>>> import random
>>> lines = open('3mil.txt').readlines()
>>> random.shuffle(lines)
>>> open('3mil.txt', 'w').writelines(lines)
To nie działa. 'shuffle' działa tylko na względnie małych listach, z grubsza 2000 elementów lub mniej. Może również nie mieć "rozsądnych" wymagań dotyczących pamięci, w zależności od długości linii. Teraz, jeśli potrzebujesz tylko "random-ish", może to wystarczy. Ale może nie. Szczegółowe informacje można znaleźć na stronie http://stackoverflow.com/questions/3062741/maximal-length-of-list-to-shuffle-with-python-random- shuffle. –
Z pewnością * działa * i działa dobrze. To, że może generować tylko 2 ** 19937 permutacji, jest banalne, graniczące z nieistotnym. Każdy shuffle oparty na RNG będzie miał to samo "ograniczenie". –
W jaki sposób rozwiązanie "sort()" jest lepsze niż 'shuffle()'? Nie unika tego rzekomego problemu. –
W wielu systemach polecenia Shell sort
trwa -R
do losowo swoje wejście.
Należy zauważyć, że opcja '-R' nadal będzie sortować identyczne linie, co może nie być pożądanym zachowaniem. –
'shuf' losuje linie bez względu na równość i jest prawdopodobnie najszybszym rozwiązaniem – fuzzyTew
Oto kolejna wersja
W powłoce użyj tego.
python decorate.py | sort | python undecorate.py
decorate.py
import sys
import random
for line in sys.stdin:
sys.stdout.write("{0}|{1}".format(random.random(), line))
undecorate.py
import sys
for line in sys.stdin:
_, _, data= line.partition("|")
sys.stdout.write(line)
Używa prawie bez pamięci.
Jak podano powyżej, 'sort -R' sortuje według klucza losowego Łatwiejszy niż dekorowanie i dekonspirowanie pliku –
@Chris B. Jak już wspomniałeś powyżej, '-R' nadal będzie grupować identyczne linie, to nie będzie, więc jeśli jest to pożądane zachowanie, to jest to sposób na pokonanie – aaronasterling
Jak wskazano powyżej,' 'shuf' losuje linie z każdą permutacją równie prawdopodobną i nie wymagającą niestandardowego kodu na początku lepiej niż pisanie i debugowanie własnego programu. –
To jest taka sama jak Pan Kugelman, ale przy użyciu vim wbudowanego interfejsu Pythona:
:py import vim, random as r; cb = vim.current.buffer ; l = cb[:] ; r.shuffle(l) ; cb[:] = l
Jeśli nie nie chcesz załadować wszystko do pamięci i sortować je tam, mają do przechowywania linii na dysku podczas sortowania losowego. To będzie bardzo powolne.
Oto bardzo prosta, głupia i wolna wersja. Zauważ, że może to zająć zaskakującą ilość miejsca na dysku i będzie bardzo powolny. Uruchomiłem go z 300 000 linii i zajmuje to kilka minut. 3 miliony linii może zająć godzinę. A więc: Zrób to w pamięci. Naprawdę. To nie jest takie duże.
import os
import tempfile
import shutil
import random
tempdir = tempfile.mkdtemp()
print tempdir
files = []
# Split the lines:
with open('/tmp/sorted.txt', 'rt') as infile:
counter = 0
for line in infile:
outfilename = os.path.join(tempdir, '%09i.txt' % counter)
with open(outfilename, 'wt') as outfile:
outfile.write(line)
counter += 1
files.append(outfilename)
with open('/tmp/random.txt', 'wt') as outfile:
while files:
index = random.randint(0, len(files) - 1)
filename = files.pop(index)
outfile.write(open(filename, 'rt').read())
shutil.rmtree(tempdir)
Inną wersją byłoby przechowywanie plików w bazie danych SQLite i losowe losowanie linii z tej bazy danych. To prawdopodobnie będzie szybsze niż to.
"To będzie bardzo powolne"? Wolniej tak. Bardzo powolny jest dyskusyjny. Każdy krok jest dość szybki. –
@ S.Lott: Cóż, zależy to od systemu plików. Użyłem ext3. 30 000 przedmiotów zajęło 5,5 sekundy. 100.000 przedmiotów zajęło 16,3 sekundy. 200.000 przedmiotów zajmuje 339 sekund. Myślę, że wyszukiwanie katalogu jest powolne z wieloma elementami. 3 miliony przedmiotów zajmie * godzin *. Przynajmniej. Baza danych może być dość szybka, ale nie mogę się poddać próbie. :-) Inną opcją byłoby odczytanie pliku i utworzenie indeksu na początkowej pozycji każdego elementu i wykonanie seek(). To powinno być szybsze niż to. –
Interesujące dane. Wydaje mi się, że spędziłem zbyt długo na bardzo dużych serwerach. –
Po prostu próbowałem tego na pliku z 4,3 M linii i najszybszą rzeczą było polecenie "shuf" na Linuksie. Użyj go tak:
shuf huge_file.txt -o shuffled_lines_huge_file.txt
Trwało 2-3 sekundy.
Oto kolejny sposób korzystania random.choice, może to zapewnić pewne stopniowe pamięci zwalnia, jak również, ale z gorszym Big-O :)
from random import choice
with open('data.txt', 'r') as r:
lines = r.readlines()
with open('shuffled_data.txt', 'w') as w:
while lines:
l = choice(lines)
lines.remove(l)
w.write(l)
"Lepszy Big-O" <- Niestety nie :-(Powtórne usunięcie w 'lines.remove (l)' daje twój algorytmowi czas pracy, który jest kwadratowy w liczbie linii. Będzie on bezużyteczny (czas działania godzin do dni) dla pliku o wartości 3 milionów wierszy –
Ups, masz rację :-) naprawiłeś to –
Poniżej Vimscript może być używany do wymiany linie:
function! Random()
let nswaps = 100
let firstline = 1
let lastline = 10
let i = 0
while i <= nswaps
exe "let line = system('shuf -i ".firstline."-".lastline." -n 1')[:-2]"
exe line.'d'
exe "let line = system('shuf -i ".firstline."-".lastline." -n 1')[:-2]"
exe "normal! " . line . 'Gp'
let i += 1
endwhile
endfunction
Wybierz funkcję w trybie wizualnym i wpisz :@"
następnie wykonać ją :call Random()
- 1. 30 milionów wierszy w MySQL
- 2. Łączenie wierszy w pandach
- 3. Manipulowanie łańcuchem o długości 30 milionów znaków
- 4. SQL - liczenie wierszy o określonej wartości
- 5. PHP MySQL wybrać losowe wierszy
- 6. Losowe wybory dwóch wartości
- 7. sed - łączenie szeregu wybranych linii
- 8. zapytania wyodrębnić losowe wierszy z tabeli
- 9. Łączenie wierszy w CLOB
- 10. Wybieranie losowe wartości z słownika
- 11. Wstaw 15 milionów linii w bazie danych DB2
- 12. łączenie wierszy ze sobą przy użyciu mysql
- 13. Raport kryształowy; Łączenie wierszy danych w pojedynczej wartości
- 14. łączenie wartości w rzędach w oparciu o dopasowanie warunków R
- 15. Wybierz losowe wierszy z tabeli mysql
- 16. Hibernate Criteria API: get n losowe wierszy
- 17. Zoptymalizuj zapytanie do tabeli z setkami milionów wierszy
- 18. Łączenie wielu linii w jedną linię
- 19. wybrać wiele wierszy o tej samej wartości (ów)
- 20. Wybierz losowe próbkowanie z sqlserver szybko
- 21. Jak wybrać losowe unikalne linie z pliku tekstowego w powłoce?
- 22. Python 3 - Łączenie z JDBC
- 23. sed: łączenie linii w zależności od drugiego
- 24. Łączenie linii z pliku tekstowego w systemie Unix?
- 25. Tworzenie losowe wartości typu rodzajowego w Java
- 26. Napisz zapytanie o samo łączenie?
- 27. Losowe próbkowanie procentowej liczby wierszy w ramce danych
- 28. Pick up linii z pliku w oparciu o numery linii w innym pliku
- 29. łączenie list o dowolnej długości
- 30. Łączenie ciągów w Railsach 3
można zobaczyć [pytanie] (http://stackoverflow.co m/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm) dla niektórych pomysłów. –
"nie udało się znaleźć prostego wyjścia." Naprawdę? Opublikuj kod, który jest zbyt skomplikowany. –
Powinienem powiedzieć: "nie udało się znaleźć wyjścia". Jestem całkiem nowy w Pythonie, więc znam tylko niektóre polecenia. Chciałem umieścić wszystko w wektorze, wybierając losową liczbę od 1 do 3 milionów, wyjąć tę linię i rozpocząć od nowa z nową liczbą losową z dodatkowym warunkiem, wyłączając poprzednie losowe liczby. Itd. Stąd moje pytanie w prosty sposób (które ty i inni dostarczyliście). Przyjmę twoje, ponieważ masz najwięcej głosów. Jednak dzięki każdemu ... wiele się nauczyłem! – Nigu