Loại bỏ các giá trị số trong các cột nhất định trong khi giữ dấu trừ?


9

Tôi có khung dữ liệu sau tiếp tục theo chiều ngang và chiều dọc vô tận với các số âm chỉ trong các cột lẻ:

-1  2  3  4 -5  9
 2  3 -4  5 -6  11

Và tôi muốn các cột hoàn chỉnh thứ 2, 4 và 6 (hoặc mỗi cột chẵn) và các dấu trừ chỉ từ cột 1, 3 và 5 (hoặc mỗi cột lẻ), vì vậy tôi nhận được điều này:

- 2   4 - 9
  3 - 5 - 11

Và cuối cùng kết thúc với điều này:

-2  4 -9
 3 -5 -11

Vì vậy, tôi cần các giá trị từ các cột chẵn không thay đổi và của các cột lẻ, nếu có giá trị âm, hãy giữ nguyên - chỉ và nếu có giá trị dương, hãy loại bỏ nó.

Có cách nào để làm điều này với awk / sed không?

Đây là khoảng cách xa như tôi nhận được:

awk '{ for (i=2;i<=NF;i+=2) $i="" }1' FILE.txt | sed 's/[0-9,.]*//g' 

Khi bạn nói dataframe của bạn tiếp tục vô tận, bạn có nghĩa là theo chiều ngang hay chiều dọc? Bạn thực sự có bao nhiêu cột?
terdon

Cả hai. Dữ liệu thử nghiệm của tôi là 3 hàng bằng 3 cột nhưng dữ liệu thực tế có số lượng khác nhau, tôi muốn nói lên 40 hàng và 40 cột.
Asfound

Câu trả lời:


2

Đây là một cách:

$ awk '{for(i=1;i<=NF;i+=2){if($i<0){$i="-"}else{$i="";} }};1' file |
     sed 's/- */-/g; s/  */ /g'
-2 4 -9
 3 -5 -11

Các awkkịch bản đi qua tất cả các cột lẻ và thiết lập giá trị của họ để -nếu họ là tiêu cực và làm rỗng nếu không muốn nói. Sau đó, sedloại bỏ bất kỳ khoảng trắng nào sau a -và sau đó thay thế nhiều khoảng trắng liên tiếp bằng một khoảng trắng. Lưu ý rằng điều này có nghĩa là căn chỉnh sẽ bị phá vỡ vì một số trường sẽ có hai ký tự trở lên và các trường khác sẽ có một ký tự. Đó sẽ không phải là vấn đề nếu bạn làm việc với các lĩnh vực, chúng trông không đẹp.


4

Các sedcách:

sed -E '
    s/^(([ \t]*-?[ \t]*[0-9.]+[ \t]+[0-9.]+)*)[ \t]+-?[ \t]*[0-9.]+$/\1/;
    s/[0-9.]+[ \t]+([0-9.]+)/\1/g'

Đầu ra:

-2  4 -9
 3 -5 -11

Biểu thức đầu tiên giết chết cột theo sau nếu có số cột lẻ. Nó thực hiện điều đó bằng cách tìm kiếm 0 hoặc nhiều cặp <number> <number>, trong đó số đầu tiên có thể âm.

Chỉnh sửa: Một sedgiải pháp ngắn hơn , lấy cảm hứng từ @mikeerv:

sed -E '
    s/[0-9.]+[ \t]*([0-9.]*)/\1/g;
    s/[- \t]*$//'

Điều tương tự với perl:

perl -lpe 's/^((\s*-?\s*[\d.]+\s*[\d.]+)*)\s+-?\s*[\d.]+$/$1/o; s/[\d.]+\s+([\d.]+)/$1/g'

Một cách khác với perl(có lẽ là cách sạch nhất):

perl -lpe '$a = 1; s/([\d.]+\s*)/$a++ % 2 ? "" : $1/eg; s/[-\s]*$//o'

Điều này hoạt động tốt trên dữ liệu thực tế của tôi miễn là tôi thêm các dấu thập phân vào tập lệnh. Cảm ơn!
Asfound

@Asfound Ok, tôi đã chỉnh sửa câu trả lời của mình để hỗ trợ các dấu thập phân.
lcd047

Đợi đã, điều này sẽ thất bại nếu có một giá trị âm làm trường (lẻ) cuối cùng.
terdon

@terdon Không thành công nếu có số cột lẻ, vâng. Nhưng có chính xác 6 cột hoặc "vô số" và "vô số" không phải là một số lẻ. :)
lcd047

OP cho biết có thể có "tối đa 40 cột" :(
terdon

3

Một perlmột:

$ perl -anle 'BEGIN{$,=" "}
  print map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}grep{!($_%2)}0..$#F' file
-2  4 -9
 3 -5 -11
  • -antách đầu vào thành @Fmảng
  • BEGIN{$,=" "} đặt dấu tách trường đầu ra thành khoảng trắng
  • grep{!($_%2)}0..$#Flấy tất cả các chỉ mục chẵn trong @Fmảng, là các chỉ mục của các phần tử lẻ
  • map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}kiểm tra xem phần tử lẻ có bắt đầu bằng không -, sau đó nối -vào phần tử chẵn tiếp theo, phần khác sẽ thêm vào khoảng trắng

3

Như câu trả lời của @ terdon nhưng không có sed:

awk '{ for(i=1;i<=NF;i+=2){
         if ($i<0) $(i+1)*=-1;
         $i = "";
       }
       print
     }'

3

Một pythongiải pháp

python -c 'from __future__ import print_function; 
import sys, math;
for line in sys.stdin:
  x = [int(y) for y in line.split()]
  print(*[int(math.copysign(b, a)) for a, b in zip(x[::2], x[1::2])], sep=" ")
' <file

2

Một awkgiải pháp dựa trên toán học đơn giản :

$ cat <<M | awk '{for(i=2;i<=NF;i+=2){printf "%4s",($(i-1)<0?-1:1)*$i}print ""}'
-1  2  3  4 -5  9
2  3.2 -4  5 -6
M

  -2   4  -9
 3.2  -5
  • Vòng lặp từ trường thứ hai ( i=2) đến trường cuối cùng ( i<=NF).
  • Nhân trường trước đó ( $(i-1)) với -1 hoặc 1.
  • Định dạng đầu ra độc đáo ( printf "%4s") và in một dòng mới ( print "").

Nhắc nhở duy nhất cho điều này là nếu bạn có số lượng cột lẻ, trường cuối cùng sẽ không hiển thị gì cả. Tôi hy vọng đây là những gì bạn mong đợi. Rõ ràng đây là những gì bạn mong đợi. :)

(được chỉnh sửa để hoạt động với các giá trị thập phân và để làm cho các điều kiện vòng lặp phù hợp hơn với câu hỏi trong khi lưu 2 ký tự.)


1

Bạn cần phải quên hoàn toàn tiêu cực - bỏ nó đi. Bạn muốn hợp nhất hai lĩnh vực - từ trái sang phải. Điều đó rất dễ dàng.

sed '   s/ *\(.*\)/\1 /
        s/\([0-9]*  *\)\{2\}/\1/g
        s/[ -]*$//
' <<\IN
-1  2  3  4 -5  9
 2  3 -4  5 -6  11
IN
-2  4 -9
3 -5 -11

Lưu ý cách tôi tránh mọi tham chiếu đến dấu hiệu - khi đầu vào được xử lý, máy tự động sẽ chỉ chấp nhận khoảng trắng hoặc số vì nó không hiểu gì khác - tất cả các thứ khác đều bị bỏ qua hoàn toàn và sẽ giữ nguyên vị trí.

Khi bạn chỉ định \{khoảng thời gian lặp lại số \}cho \(biểu hiện phụ \), chỉ lần xuất hiện cuối cùng của biểu thức đó được \1tham chiếu lại. Vì vậy, bạn có thể chỉ cần bóp - hoặc cắt ngắn - một khoảng lặp lại dễ dàng. Và bởi vì chúng ta siết chặt lặp lại đằng sau dấu hiệu - nếu có một - sự xuất hiện thứ hai của mẫu đó sẽ theo bất kỳ dấu hiệu nào được sử dụng trước dấu hiệu đầu tiên.

Hành vi được mô tả ở trên được POSIX chỉ định cho tất cả các ứng dụng tuân thủ BRE, nhưng rất ít người sedhiểu đúng. GNU sednào.

Cuối cùng, các không gian chỉ là để làm cho mô hình xuất hiện thường xuyên .

Tất nhiên, điều này sẽ không bao giờ làm việc cho bạn. Hoặc, có lẽ chính xác hơn, nó sẽ luôn làm việc cho bạn, nhưng không bao giờ trả lại bất kỳ kết quả nào. Làm thế nào nó có thể nếu mô hình là vô thời hạn ?


Điều này sẽ chỉ hoạt động nếu có một số lượng chẵn các lĩnh vực.
terdon

@terdon - Không - nó hoạt động cho bất cứ điều gì.
mikeerv

Không, hãy thử nó với một số lượng lớn các lĩnh vực. Cái cuối cùng được in và nó không nên.
terdon

@terdon - Tại sao không nên? Không có trường nào sau đây để hủy bỏ nó? Người hỏi nói rằng họ muốn xóa các cột lẻ theo sau là một cột chẵn. Cột cuối cùng không được theo sau bởi một cột chẵn - nó thực hiện chính xác những gì nó cần và loại bỏ càng ít càng tốt. Giả sử một số dữ liệu nên đi là thực tế xấu theo ý kiến ​​của tôi.
mikeerv

Không, họ không: "Vì vậy, tôi cần các giá trị từ các cột chẵn không thay đổi và của các cột lẻ, nếu có giá trị âm, hãy giữ nguyên - chỉ và nếu có giá trị dương, hãy loại bỏ nó." Các trường lẻ không bao giờ được in, thông tin duy nhất họ nên truyền đạt là liệu chúng có âm hay không. Bạn in trường lẻ tích cực.
terdon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.